simple_form: What is the expected slowdown of using SimpleForm?
I was investigating some slow view rendering in our application.
We had a partial that was rendered many times, which looked like this. I had perhaps stupidly opted out of most Simple Form goodness, but I guess for consistency’s sake, thought this would be ok.
<div class='sortableItem variant' data-item-id='<%= f.object.id %>'>
<div class="variant-creator-row">
<div class="variant-details">
<%= f.input :text, label: false, wrapper: false, as: :string %>
</div>
<div class="variant-option-value">
<%= f.input :option_1_value, label: false, wrapper: false %>
</div>
<div class="variant-option-value">
<%= f.input :option_2_value, label: false, wrapper: false %>
</div>
<div class="variant-option-value">
<%= f.input :option_3_value, label: false, wrapper: false %>
</div>
<div class="variant-hidden">
<%= f.input :hidden, label: false, wrapper: false %>
</div>
<div class="variant-delete survey-answer-delete">
<a href="#" class="text text-danger">delete</a>
<div class="hidden">
<%= f.input_field :_destroy, as: :boolean, label: false, wrapper: false %>
</div>
</div>
</div>
</div>
<%= f.hidden_field :field_kind, value: 'multiple_choice' %>
Worth noting, this f value is coming from a “simple_fields_for” call.
This partial was getting rendered many times, and looking at my logs, each one was taking > 200 milliseconds! eek! https://gist.github.com/maxwell/12cd7e949cae4ea60766
Changing this to just be normal Rails helpers radically reduced render time, to about 5 milliseconds per partial, 40x faster!
https://gist.github.com/maxwell/f7b6c1bc6625f6b5c3e7
I realize that it is reasonable to know that there would be some overhead, and perhaps one should not use SimpleForms for simple forms which are rendered many times, but is this the kind of overhead we should expect? Am I doing something incredibly stupid to cause this behavior?
I am currently using simple_form (3.1.0.rc1), and Rails 4.1.10
I love using SimpleForm, thanks so much for all the hard work you guys put into it!
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Comments: 40 (11 by maintainers)
Commits related to this issue
- Sped up rendering of form by a large amount See https://github.com/plataformatec/simple_form/issues/1227 for some more details. Also added slim and started translating some templates. — committed to swissdrg/webgrouper by panmari 9 years ago
- Remove nested (slow) i18n lookups SimpleForm looks up for translation in a huge amount of places which slows it down when you use nested forms. See issue: https://github.com/plataformatec/simple_for... — committed to stayhero/simple_form by stayhero 9 years ago
- Disable binding_of_caller for faster dev rendering See these bugs: https://github.com/plataformatec/simple_form/issues/1237 https://github.com/plataformatec/simple_form/issues/1227 — committed to department-of-veterans-affairs/SCIInterim by awong-dev 9 years ago
- Upgrade SimpleForm Upgrades SimpleForm from 3.1.0rc2 to 3.20. A noticeable performance decrease was spotted when rendering views in the app after updating to Rails from 4.2.0 to 4.2.4 - in most case... — committed to hmcts/et-pet-et1 by dan-palmer 9 years ago
3.2.0 released with the performance fix. Thanks everyone!
@josevalim I will corroborate the conclusions of others on this thread that i18n MissingTranslations is the culprit.
I think the
binding_of_caller“slowdown” is a magnification of an underlying issues.Running a reduced version of my view through ruby-prof, the number of calls to
I18n::Backend::Base#translategoes from 98 to 6281 when I add in asimple_fields_forcall which renders a partial. The partial in question only has ~200 inputs which should result in O(6000x) more calls to translate. There is some sort of non-linear behavior going on in simple_fields_for. I think it’s related to interactions withI18n::MissingTranslationin SimpleForms. If you add the following monkey patch to config/initializers somewhere:The raises of
I18n::MissingTranslationdisappear from the profile and performance returns (I’m dropping from 4s/page load down to 700ms).I think the reason
binding_of_calleris causing a drastic slowdown is becauseActionView::Helpers::TranslationHelper#translateraises for a unknown translation key. For each raise (of which we now have thousands),better_errorscallsBetterErrors::ExceptionExtension#set_backtracewhich invokesBindingOfCaller::BindingExtensions#callers. This, at minimum, done some array allocation/deallocation in addition to a stack walk.Just to be completely thorough, I wanted to verify that MRI2’s stack walk code wasn’t somehow causing a huge slowdown (it shouldn’t since it’s some very straightforward pointer math). To do this, I downloaded
binding_of_callerand stubbed outBindingOfCaller::BindingExtensions#callersto just return an empty array. Things did not get appreciably faster in this case.Hope this helps!