Статьи

Сделайте свой редактор на основе Xtext в 300 раз быстрее *

Мои искренние извинения за нашумевшее название. Вот мелкий шрифт: с трехстрочным изменением кода мы смогли сделать редактор Protocol Buffer ~ в 300 раз быстрее при открытии файлов в проекте Java. Улучшения скорости могут варьироваться в зависимости от размера пути к классам проекта.

Некоторый фон

В Google наши проекты Eclipse больше, чем я когда-либо видел: путь к классам проекта может легко содержать от 4000 до 8000 файлов jar! В результате любые проблемы с производительностью, даже незначительные, значительно усиливаются в нашей среде. Частые задержки и зависания делают использование Eclipse разочаровывающим.

Одна из целей моей команды — сделать Eclipse способным справляться с нашими гигантскими проектами. Чтобы найти проблемы с производительностью (а затем и исправить их), мы регистрируем задержки в потоке пользовательского интерфейса Eclipse. В наших журналах мы обнаружили, что одним из пяти основных нарушителей был, к моему удивлению, Xtext .

Эта проблема

Прежде чем я продолжу, я хотел бы уточнить, что я не хочу разбивать Xtext. ИМХО, Xtext потрясающий и выполняет свое обещание: создать полноценный редактор из определения грамматики. Я считаю Xtext одним из трех лучших проектов Eclipse всех времен.

Хорошо, вернемся к нашей проблеме. Согласно нашим журналам, Xtext требуется несколько секунд, чтобы открыть документ (в нашем случае файл .proto.) Мы использовали Xtext 2.0.3 M6 и Eclipse 3.8 M6, BTW.

Трассировка зарегистрированного стека выглядит следующим образом:

java.util.zip.ZipFile.(ZipFile.java:131)
java.util.jar.JarFile.(JarFile.java:150)
java.util.jar.JarFile.(JarFile.java:114)
org.eclipse.xtext.ui.resource.XtextResourceSetProvider.computePlatformURIMap(XtextResourceSetProvider.java:68)
org.eclipse.xtext.ui.resource.XtextResourceSetProvider.get(XtextResourceSetProvider.java:49)
org.eclipse.xtext.ui.editor.model.ResourceForIEditorInputFactory.getResourceSet(ResourceForIEditorInputFactory.java:89)
org.eclipse.xtext.ui.editor.model.JavaClassPathResourceForIEditorInputFactory.getResourceSet(JavaClassPathResourceForIEditorInputFactory.java:59)
org.eclipse.xtext.ui.editor.model.ResourceForIEditorInputFactory.createResourceFor(ResourceForIEditorInputFactory.java:68)
org.eclipse.xtext.ui.editor.model.ResourceForIEditorInputFactory.createResource(ResourceForIEditorInputFactory.java:64)
org.eclipse.xtext.ui.editor.model.JavaClassPathResourceForIEditorInputFactory.createResource(JavaClassPathResourceForIEditorInputFactory.java:37)
org.eclipse.xtext.ui.editor.model.ResourceForIEditorInputFactory.createResource(ResourceForIEditorInputFactory.java:53)
org.eclipse.xtext.ui.editor.model.XtextDocumentProvider.setDocumentContent(XtextDocumentProvider.java:118)

Согласно коду XtextResourceSetProvider, при создании документа Xtext (например, открытие файла .proto) Xtext считывает манифест в каждом отдельном банке в пути к классам. Учитывая огромные пути к классам в наших проектах, это сканирование может занять значительное время.

Поскольку мы так и не получили четкого ответа, почему Xtext делает это, у нас было два варианта:

  1. Прочитайте код Xtext и EMF, чтобы понять проблему. Чтение слоев недокументированного кода не так плохо, как кажется. Однако для понимания кода и его исправления требуется время. К сожалению, у меня его нет. Другие проекты требуют моего немедленного внимания.
  2. Сделайте обоснованное предположение, чтобы решить проблему. Продолжайте читать, пожалуйста.

Решение

Мы пошли на альтернативу «образованное предположение». При условии:

  1. мы обнаружили, что редактор прототипов хорошо работает в не-Java проектах (например, в CDT ,)
  2. мы подозревали, что это сканирование пути к классам было необходимо для пользовательских языков на основе JVM (таких как Xtend ,) и
  3. язык протокола Buffer не зависит от типов JVM

мы были вполне уверены, что сканирование пути к классам проекта не добавило никакой ценности, и мы могли безопасно удалить его.

Изменение буквально потребовало добавления 3 строк кода. Прелесть Xtext в том, что использует Guice под одеялом. Нам нужно было только заменить XtextResourceSetProvider другой реализацией IResourceSetProvider в модуле проекта пользовательского интерфейса:

@Override public Class<? extends IResourceSetProvider> bindIResourceSetProvider() {
    return SimpleResourceSetProvider.class;
  }

Вот и все!

В следующей таблице показано значительное улучшение производительности. Пожалуйста, обратите внимание на смехотворное количество времени, которое затрачивалось на открытие небольших файлов.

LOC Время открывать
Перед После
199 5280 мс 17 мс
19 3885 мс 6 мс
27 2033 мс 7 мс

Обратите внимание, что строки кода — не единственная метрика, которая влияет на производительность. Есть и другие факторы (например, область видимости), которые необходимо учитывать при измерении производительности.

Мы не потеряли никакой функциональности в наших редакторах после внесения этих изменений. Подсветка синтаксиса, помощь по содержанию, определение объема, гиперссылка и проверка работали нормально.

Вывод

Xtext — отличная среда для создания редакторов для пользовательских языков. Хотя это зрелый проект, все еще есть возможности для улучшения. В этой статье я показал вам, как мы значительно улучшили производительность нашего редактора на основе Xtext с помощью всего лишь нескольких строк кода. Мы смогли устранить проблему в рекордно короткие сроки, используя комбинацию данных, фактов и интуиции.

Обратная связь всегда приветствуется ?