From 5fa5c2aa232f12aeba124662b9382d55c687a37b Mon Sep 17 00:00:00 2001 From: AlenaK Date: Sun, 15 Oct 2023 21:29:47 +0500 Subject: [PATCH] task_1 --- benchmark-test.rb | 13 + case-study.md | 82 + performance_spec.rb | 28 + ruby_prof.rb | 24 + ruby_prof_reports/callstack_end.html | 962 +++++++ ruby_prof_reports/callstack_start.html | 1002 +++++++ ruby_prof_reports/flat_end.txt | 69 + ruby_prof_reports/flat_start.txt | 73 + ruby_prof_reports/graph_end.html | 3023 +++++++++++++++++++++ ruby_prof_reports/graph_start.html | 3359 ++++++++++++++++++++++++ stackprof_reports/stackprof.dump | Bin 0 -> 2703 bytes task-1.rb | 135 +- test_me.rb | 36 + 13 files changed, 8702 insertions(+), 104 deletions(-) create mode 100644 benchmark-test.rb create mode 100644 case-study.md create mode 100644 performance_spec.rb create mode 100644 ruby_prof.rb create mode 100644 ruby_prof_reports/callstack_end.html create mode 100644 ruby_prof_reports/callstack_start.html create mode 100644 ruby_prof_reports/flat_end.txt create mode 100644 ruby_prof_reports/flat_start.txt create mode 100644 ruby_prof_reports/graph_end.html create mode 100644 ruby_prof_reports/graph_start.html create mode 100644 stackprof_reports/stackprof.dump create mode 100644 test_me.rb diff --git a/benchmark-test.rb b/benchmark-test.rb new file mode 100644 index 00000000..e306bb45 --- /dev/null +++ b/benchmark-test.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'benchmark/ips' +require_relative 'task-1' + +Benchmark.ips do |x| + x.config(stats: :bootstrap, confidance: 95) + + x.report('10_000') { work('data_10_000.txt') } + x.report('20_000') { work('data_20_000.txt') } + x.report('40_000') { work('data_40_000.txt') } + x.compare! +end diff --git a/case-study.md b/case-study.md new file mode 100644 index 00000000..1c3a9f48 --- /dev/null +++ b/case-study.md @@ -0,0 +1,82 @@ +# Case-study оптимизации + +## Актуальная проблема +В нашем проекте возникла серьёзная проблема. + +Необходимо было обработать файл с данными, чуть больше ста мегабайт. + +У нас уже была программа на `ruby`, которая умела делать нужную обработку. + +Она успешно работала на файлах размером пару мегабайт, но для большого файла она работала слишком долго, и не было понятно, закончит ли она вообще работу за какое-то разумное время. + +Я решил исправить эту проблему, оптимизировав эту программу. + +## Формирование метрики +Для того, чтобы понимать, дают ли мои изменения положительный эффект на быстродействие программы я придумал использовать такую метрику: время обработки файла на 10 000 строк в секундах + +## Гарантия корректности работы оптимизированной программы +Программа поставлялась с тестом. Выполнение этого теста в фидбек-лупе позволяет не допустить изменения логики программы при оптимизации. + +## Feedback-Loop +Для того, чтобы иметь возможность быстро проверять гипотезы я выстроил эффективный `feedback-loop`, который позволил мне получать обратную связь по эффективности сделанных изменений за несколько минут. + +Вот как я построил `feedback_loop`: +- профилирование, поиск точки роста +- оптимизация bottleneck'а +- тестрование +- прогон benchmark +- если уложились в бюджет - коммитим изменения, иначе повторяем алгоритм + +## Вникаем в детали системы, чтобы найти главные точки роста +Для того, чтобы найти "точки роста" для оптимизации я воспользовался профилировщиком ruby-prof + +Вот какие проблемы удалось найти и решить + +### Находка №1 +- ruby-prof в формате callstack показал, что первая точка роста - Array#select: +`user_sessions = sessions.select { |session| session['user_id'] == user['id'] }` +- группировка сессии по пользователям +- время обработки сократилось с 7,73 s до 1,03 s +- да. %self: 87% -> 0% + +### Находка №2 +- ruby-prof в формате flat показал, что следующая точка роста Array#all? +- получение списка уникальных браузеров через map и uniq: +`unique_browsers = sessions.map { |session| session['browser'] }.uniq` +- время выполнения сократилось с 1,03 s до 0,37 s +- да. %self: 26,1% -> 0,35% + +### Находка №3 +- ruby-prof в формате callstack -> `collect_stats_from_users` +- уменьшение числа вызовов метода, внутри метода сокращено количество вызовов map, по подсказке рубокопа конкатенация строк заменена на интерполяцию +- с 0,36 s до 0,29 s +- да + +### Находка №4 +- ruby-prof в формате flat -> Array#+ +- заменила на `<<` +`users_objects = users.map { |user| User.new(attributes: user, sessions: sessions_by_users[user['id']] || []) }` +- c 0,29 s до 0,23 s +- да. %self: 19,24% -> 0% + +### Находка №5 +- ruby-prof в формате flat -> Array#each +- замена на map +- 0,2391 s -> 0,2214 s +- да + +### Находка №6 +- ruby-prof в формате flat -> String#split +- убран из методов `parse_user` и `parse_session`, сразу передается массив +- 0,2214 s -> 0,2109 s +- да. %self: 18,6% -> 9,86% + +## Результаты +В результате проделанной оптимизации наконец удалось обработать файл с данными. +Удалось улучшить метрику системы и уложиться в заданный бюджет. После проделанной работы обработка файла занимает ~40 s. + +Обработка файла в 10 000 строк занимала ~7,72 с, после оптимизации время сократилось в 37 раз и стало ~0,21 с + +## Защита от регрессии производительности +Для защиты от потери достигнутого прогресса при дальнейших изменениях программы были написаны performance-тесты, которые контролируют укладывается ли выполнение в заданный бюджет. Рассмотрены кейсы для файлов: 10 000, 20 000 и 40 000 строк, с бюджетом 100, 200 и 400 мс соответственно. + diff --git a/performance_spec.rb b/performance_spec.rb new file mode 100644 index 00000000..4ef63c24 --- /dev/null +++ b/performance_spec.rb @@ -0,0 +1,28 @@ +require 'rspec' +require 'rspec-benchmark' +require_relative 'task-1.rb' + +RSpec.configure do |config| + config.include RSpec::Benchmark::Matchers +end + +describe 'data 10_000' do + it 'perform less 100 ms' do + file_lines = File.read('data_large.txt').split("\n").first(10_000) + expect { collect_stats(file_lines) }.to perform_under(100).ms.warmup(2).times.sample(10).times + end +end + +describe 'data 20_000' do + it 'perform less 200 ms' do + file_lines = File.read('data_large.txt').split("\n").first(20_000) + expect { collect_stats(file_lines) }.to perform_under(200).ms.warmup(2).times.sample(10).times + end +end + +describe 'data 40_000' do + it 'perform less 400 ms' do + file_lines = File.read('data_large.txt').split("\n").first(40_000) + expect { collect_stats(file_lines) }.to perform_under(400).ms.warmup(2).times.sample(10).times + end +end diff --git a/ruby_prof.rb b/ruby_prof.rb new file mode 100644 index 00000000..2bad497f --- /dev/null +++ b/ruby_prof.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'ruby-prof' +require_relative 'task-1' + +RubyProf.measure_mode = RubyProf::WALL_TIME + +result = RubyProf.profile do + file_lines = File.read('data_large.txt').split("\n").first(10_000) + collect_stats(file_lines) +end + +# _#{Time.new.to_i} +printer1 = RubyProf::FlatPrinter.new(result) +printer1.print(File.open("ruby_prof_reports/flat_#{Time.new.to_i}.txt", 'w+')) + +printer2 = RubyProf::GraphHtmlPrinter.new(result) +printer2.print(File.open("ruby_prof_reports/graph_#{Time.new.to_i}.html", 'w+')) + +printer3 = RubyProf::CallStackPrinter.new(result) +printer3.print(File.open("ruby_prof_reports/callstack_#{Time.new.to_i}.html", 'w+')) + +printer4 = RubyProf::CallTreePrinter.new(result) +printer4.print(:path => "ruby_prof_reports", :profile => 'callgrind') diff --git a/ruby_prof_reports/callstack_end.html b/ruby_prof_reports/callstack_end.html new file mode 100644 index 00000000..1ea16af7 --- /dev/null +++ b/ruby_prof_reports/callstack_end.html @@ -0,0 +1,962 @@ + + + + + ruby-prof call tree + + + + + + + +
+
+ Call tree for application ruby_prof.rb
Generated on 2023-10-15 19:52:08 +0500 + with options {}
+
+
+ Threshold: + + + + + +
+ + + + +
+ Thread: 260, Fiber: 240 (100.00% ~ 0.21090375899802893) +
    + +
  • + +100.00% (100.00%) [global]# [1 calls, 1 total] +
      +
    • + +99.96% (99.96%) Object#work [1 calls, 1 total] +
        +
      • + +52.34% (52.37%) Object#collect_stats_from_users [1 calls, 1 total] +
          +
        • + +52.34% (100.00%) Array#each [1 calls, 3 total] +
            +
          • + +37.60% (71.83%) Array#map [6144 calls, 6147 total] +
              +
            • + +26.58% (70.70%) <Class::Date>#parse [8464 calls, 8464 total] +
                +
              • + +5.70% (21.44%) Regexp#match [16928 calls, 16928 total] +
              • +
              • + +3.44% (12.92%) String#gsub! [8464 calls, 8464 total] +
              • +
              • + +2.17% (8.15%) MatchData#begin [8464 calls, 8464 total] +
              • +
              • + +1.26% (4.73%) String#[]= [8464 calls, 8464 total] +
              • + + +
              +
            • +
            • + +2.08% (5.54%) Date#iso8601 [8464 calls, 8464 total] +
            • + + +
            +
          • +
          • + +3.56% (6.80%) Array#sort [3072 calls, 3073 total] +
              +
            • + +1.35% (38.05%) Date#<=> [14789 calls, 14789 total] +
            • +
            +
          • +
          • + +2.03% (3.88%) Array#any? [1536 calls, 1536 total] +
              +
            • + +1.12% (55.18%) String#=~ [4492 calls, 6471 total] +
            • +
            +
          • + + + + + + + + + + +
          +
        • +
        +
      • +
      • + +36.69% (36.71%) Array#each [1 calls, 3 total] +
          +
        • + +10.14% (27.65%) Object#parse_session [8464 calls, 8464 total] +
            +
          • + +3.44% (33.95%) Array#[] [42320 calls, 68464 total] +
          • +
          +
        • +
        • + +9.01% (24.55%) String#split [10000 calls, 10001 total] +
        • +
        • + +1.99% (5.43%) String#== [20000 calls, 20000 total] +
        • +
        • + +1.72% (4.68%) Array#[] [20000 calls, 68464 total] +
        • +
        • + +1.48% (4.02%) Object#parse_user [1536 calls, 1536 total] +
            + +
          +
        • +
        • + +1.20% (3.27%) Array#<< [10000 calls, 10000 total] +
        • +
        +
      • +
      • + +4.16% (4.17%) Array#map [3 calls, 6147 total] +
          +
        • + +1.62% (38.97%) Class#new [1536 calls, 1536 total] + +
        • + + +
        +
      • +
      • + +2.99% (2.99%) Enumerable#group_by [1 calls, 1 total] +
          +
        • + +2.99% (99.87%) Array#each [1 calls, 3 total] +
        • +
        +
      • +
      • + +1.34% (1.34%) JSON::Ext::Generator::GeneratorMethods::Hash#to_json [1 calls, 1 total] +
          + +
        +
      • + + + + + + + + +
      +
    • +
    +
  • + +
+
+ +
+
+ + diff --git a/ruby_prof_reports/callstack_start.html b/ruby_prof_reports/callstack_start.html new file mode 100644 index 00000000..287f42cb --- /dev/null +++ b/ruby_prof_reports/callstack_start.html @@ -0,0 +1,1002 @@ + + + + + ruby-prof call tree + + + + + + + +
+
+ Call tree for application ruby_prof.rb
Generated on 2023-10-15 14:43:02 +0500 + with options {}
+
+
+ Threshold: + + + + + +
+ + + + +
+ Thread: 260, Fiber: 240 (100.00% ~ 7.726320823996502) +
    + +
  • + +100.00% (100.00%) [global]# [1 calls, 1 total] +
      +
    • + +100.00% (100.00%) Object#work [1 calls, 1 total] +
        +
      • + +97.36% (97.36%) Array#each [3 calls, 10 total] +
          +
        • + +87.39% (89.77%) Array#select [1536 calls, 1536 total] +
            +
          • + +23.42% (26.80%) String#== [13000704 calls, 13861980 total] +
          • +
          +
        • +
        • + +7.71% (7.92%) Array#all? [8464 calls, 10000 total] +
            +
          • + +4.42% (57.34%) BasicObject#!= [841276 calls, 841276 total] +
              +
            • + +1.56% (35.41%) String#== [841276 calls, 13861980 total] +
            • +
            +
          • +
          +
        • + + + + + + + +
        +
      • +
      • + +2.45% (2.45%) Object#collect_stats_from_users [7 calls, 7 total] +
          +
        • + +2.45% (99.99%) Array#each [7 calls, 10 total] +
            +
          • + +1.27% (51.75%) Array#map [16896 calls, 16898 total] +
              + + + + +
            +
          • + + + + + + + + + + + + + + + +
          +
        • +
        +
      • + + + + + + + + + + +
      +
    • +
    +
  • + +
+
+ +
+
+ + diff --git a/ruby_prof_reports/flat_end.txt b/ruby_prof_reports/flat_end.txt new file mode 100644 index 00000000..97f9d630 --- /dev/null +++ b/ruby_prof_reports/flat_end.txt @@ -0,0 +1,69 @@ +Measure Mode: wall_time +Thread ID: 260 +Fiber ID: 240 +Total: 0.210904 +Sort by: self_time + + %self total self wait child calls name location + 19.09 0.194 0.040 0.000 0.154 3 Array#each + 12.48 0.056 0.026 0.000 0.030 8464 #parse + 9.86 0.021 0.021 0.000 0.000 10001 String#split + 9.34 0.088 0.020 0.000 0.068 6147 Array#map + 6.70 0.021 0.014 0.000 0.007 8464 Object#parse_session /home/user/projects/optimization/rails-optimization-task1/task-1.rb:23 + 5.70 0.012 0.012 0.000 0.000 16928 Regexp#match + 5.66 0.012 0.012 0.000 0.000 68464 Array#[] + 3.44 0.007 0.007 0.000 0.000 8464 String#gsub! + 2.23 0.008 0.005 0.000 0.003 3073 Array#sort + 2.17 0.005 0.005 0.000 0.000 8464 MatchData#begin + 2.08 0.004 0.004 0.000 0.000 8464 Date#iso8601 + 1.99 0.004 0.004 0.000 0.000 20000 String#== + 1.53 0.003 0.003 0.000 0.000 6471 String#=~ + 1.35 0.003 0.003 0.000 0.000 14789 Date#<=> + 1.34 0.003 0.003 0.000 0.000 1 JSON::Ext::Generator::GeneratorMethods::Hash#to_json + 1.33 0.003 0.003 0.000 0.001 1536 Class#new + 1.26 0.003 0.003 0.000 0.000 8464 String#[]= + 1.20 0.003 0.003 0.000 0.000 10000 Array#<< + 1.02 0.002 0.002 0.000 0.000 8664 String#upcase + 0.99 0.002 0.002 0.000 0.000 3073 Hash#[]= + 0.97 0.003 0.002 0.000 0.001 1536 Object#parse_user /home/user/projects/optimization/rails-optimization-task1/task-1.rb:14 + 0.91 0.004 0.002 0.000 0.002 1536 Array#any? + 0.88 0.002 0.002 0.000 0.000 8464 String#to_i + 0.83 0.002 0.002 0.000 0.000 8464 Integer#div + 0.71 0.002 0.002 0.000 0.000 8464 MatchData#end + 0.69 0.001 0.001 0.000 0.000 1 Array#uniq + 0.68 0.001 0.001 0.000 0.000 1 #write + 0.65 0.001 0.001 0.000 0.000 1537 Array#join + 0.49 0.001 0.001 0.000 0.000 6144 User#sessions + 0.45 0.001 0.001 0.000 0.000 3072 Hash#[] + 0.44 0.002 0.001 0.000 0.001 1536 Array#all? + 0.29 0.001 0.001 0.000 0.000 1536 User#initialize /home/user/projects/optimization/rails-optimization-task1/task-1.rb:8 + 0.28 0.001 0.001 0.000 0.000 3072 User#attributes + 0.24 0.001 0.001 0.000 0.000 1536 Array#reverse + 0.18 0.000 0.000 0.000 0.000 1536 Array#sum + 0.16 0.000 0.000 0.000 0.000 1536 Array#max + 0.15 0.000 0.000 0.000 0.000 1539 Array#count + 0.11 0.000 0.000 0.000 0.000 1 #read + 0.06 0.211 0.000 0.000 0.211 1 Object#work /home/user/projects/optimization/rails-optimization-task1/task-1.rb:41 + 0.04 0.211 0.000 0.000 0.211 1 [global]# ruby_prof.rb:7 + 0.00 0.006 0.000 0.000 0.006 1 Enumerable#group_by + 0.00 0.110 0.000 0.000 0.110 1 Object#collect_stats_from_users /home/user/projects/optimization/rails-optimization-task1/task-1.rb:33 + 0.00 0.000 0.000 0.000 0.000 1 JSON::Ext::Generator::State#initialize + +* recursively called methods + +Columns are: + + %self - The percentage of time spent in this method, derived from self_time/total_time. + total - The time spent in this method and its children. + self - The time spent in this method. + wait - The amount of time this method waited for other threads. + child - The time spent in this method's children. + calls - The number of times this method was called. + name - The name of the method. + location - The location of the method. + +The interpretation of method names is: + + * MyObject#test - An instance method "test" of the class "MyObject" + * #test - The <> characters indicate a method on a singleton class. + diff --git a/ruby_prof_reports/flat_start.txt b/ruby_prof_reports/flat_start.txt new file mode 100644 index 00000000..9c14447d --- /dev/null +++ b/ruby_prof_reports/flat_start.txt @@ -0,0 +1,73 @@ +Measure Mode: wall_time +Thread ID: 260 +Fiber ID: 240 +Total: 7.726321 +Sort by: self_time + + %self total self wait child calls name location + 63.97 6.752 4.942 0.000 1.810 1536 Array#select + 25.03 1.934 1.934 0.000 0.000 13861980 String#== + 3.30 0.598 0.255 0.000 0.343 10000 Array#all? + 2.85 0.341 0.221 0.000 0.121 841276 BasicObject#!= + 1.05 7.711 0.081 0.000 7.630 10 Array#each + 0.74 0.057 0.057 0.000 0.000 11736 Array#+ + 0.52 0.040 0.040 0.000 0.000 20001 String#split + 0.51 0.104 0.040 0.000 0.065 16898 Array#map + 0.34 0.053 0.027 0.000 0.026 8464 #parse + 0.18 0.035 0.014 0.000 0.021 8464 Object#parse_session /home/user/projects/optimization/rails-optimization-task1/task-1.rb:26 + 0.13 0.010 0.010 0.000 0.000 24576 String#+ + 0.12 0.009 0.009 0.000 0.000 68464 Array#[] + 0.12 0.009 0.009 0.000 0.000 16928 Regexp#match + 0.09 0.007 0.007 0.000 0.000 8464 String#gsub! + 0.08 0.009 0.006 0.000 0.003 3073 Array#sort + 0.08 0.008 0.006 0.000 0.002 1536 Class#new + 0.07 0.006 0.006 0.000 0.000 21504 Hash#[] + 0.07 0.006 0.006 0.000 0.000 10752 Hash#merge + 0.07 0.005 0.005 0.000 0.000 23399 String#upcase + 0.07 0.005 0.005 0.000 0.000 12289 Hash#[]= + 0.06 0.005 0.005 0.000 0.000 8464 Date#iso8601 + 0.06 0.005 0.005 0.000 0.000 8464 MatchData#begin + 0.05 0.007 0.004 0.000 0.003 1536 Object#parse_user /home/user/projects/optimization/rails-optimization-task1/task-1.rb:16 + 0.04 0.003 0.003 0.000 0.000 21504 User#attributes + 0.04 0.003 0.003 0.000 0.000 16928 String#to_i + 0.04 0.003 0.003 0.000 0.000 1 JSON::Ext::Generator::GeneratorMethods::Hash#to_json + 0.04 0.003 0.003 0.000 0.000 6471 String#=~ + 0.04 0.003 0.003 0.000 0.000 14789 Date#<=> + 0.03 0.002 0.002 0.000 0.000 8464 String#[]= + 0.03 0.005 0.002 0.000 0.003 1536 Array#any? + 0.03 0.002 0.002 0.000 0.000 1536 User#initialize /home/user/projects/optimization/rails-optimization-task1/task-1.rb:10 + 0.03 0.002 0.002 0.000 0.000 10752 User#sessions + 0.02 0.002 0.002 0.000 0.000 8464 Integer#div + 0.02 0.001 0.001 0.000 0.000 8464 MatchData#end + 0.02 0.001 0.001 0.000 0.000 1 #write + 0.01 0.001 0.001 0.000 0.000 1537 Array#join + 0.01 0.001 0.001 0.000 0.000 3072 Integer#to_s + 0.01 0.000 0.000 0.000 0.000 1 Array#uniq + 0.00 0.000 0.000 0.000 0.000 1536 Array#reverse + 0.00 0.000 0.000 0.000 0.000 1536 Array#sum + 0.00 0.000 0.000 0.000 0.000 1536 Array#max + 0.00 0.000 0.000 0.000 0.000 1 #read + 0.00 0.000 0.000 0.000 0.000 1539 Array#count + 0.00 7.726 0.000 0.000 7.726 1 Object#work /home/user/projects/optimization/rails-optimization-task1/task-1.rb:45 + 0.00 7.726 0.000 0.000 7.726 1 [global]# ruby_prof.rb:7 + 0.00 0.189 0.000 0.000 0.189 7 Object#collect_stats_from_users /home/user/projects/optimization/rails-optimization-task1/task-1.rb:37 + 0.00 0.000 0.000 0.000 0.000 1 JSON::Ext::Generator::State#initialize + +* recursively called methods + +Columns are: + + %self - The percentage of time spent in this method, derived from self_time/total_time. + total - The time spent in this method and its children. + self - The time spent in this method. + wait - The amount of time this method waited for other threads. + child - The time spent in this method's children. + calls - The number of times this method was called. + name - The name of the method. + location - The location of the method. + +The interpretation of method names is: + + * MyObject#test - An instance method "test" of the class "MyObject" + * #test - The <> characters indicate a method on a singleton class. + diff --git a/ruby_prof_reports/graph_end.html b/ruby_prof_reports/graph_end.html new file mode 100644 index 00000000..e7dc32f4 --- /dev/null +++ b/ruby_prof_reports/graph_end.html @@ -0,0 +1,3023 @@ + + + + + + +
+
+
+
Profile Report
+

Wall_time

+
+
+
Sunday, October 15 at 7:52:08 PM (+05)
+ +
+
+
+
+ + + + + + + + + + + + + +
Thread IDFiber IDTotal
2602400.21090375899802893
+ + + +

Thread 260, Fiber: 240

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
%Total%SelfTotalSelfWaitChildCallsNameLine
100.00%0.04%0.210.000.000.211 + + [global]# + + 7
  0.210.000.000.211/1Object#work7 +
  0.210.000.000.211/1[global]#7
99.96%0.06%0.210.000.000.211 + + Object#work + + 41
  0.110.000.000.111/1Object#collect_stats_from_users89 +
  0.080.020.000.051/3Array#each47 +
  0.010.000.000.003/6147Array#map73 +
  0.010.000.000.011/1Enumerable#group_by81 +
  0.000.000.000.001/1JSON::Ext::Generator::GeneratorMethods::Hash#to_json103 +
  0.000.000.000.001/10001String#split42 +
  0.000.000.000.001/1Array#uniq73 +
  0.000.000.000.001/1<Class::IO>#write103 +
  0.000.000.000.001/1<Class::IO>#read42 +
  0.000.000.000.001/3073Array#sort79 +
  0.000.000.000.001/1537Array#join79 +
  0.000.000.000.003/1539Array#count70 +
  0.000.000.000.001/3073Hash#[]=70 +
  0.010.010.000.001/3Enumerable#group_by
  0.080.020.000.051/3Object#work47
  0.110.010.000.101/3Object#collect_stats_from_users34
92.01%19.09%0.190.040.000.153 + + Array#each + +
  0.080.010.000.066144/6147Array#map90 +
  0.020.010.000.018464/8464Object#parse_session50 +
  0.020.020.000.0010000/10001String#split48 +
  0.010.000.000.003072/3073Array#sort93 +
  0.000.000.000.001536/1536Array#any?93 +
  0.000.000.000.0020000/20000String#==49 +
  0.000.000.000.0020000/68464Array#[]49 +
  0.000.000.000.001536/1536Object#parse_user49 +
  0.000.000.000.0010000/10000Array#<<49 +
  0.000.000.000.003072/3073Hash#[]=36 +
  0.000.000.000.001536/1536Array#all?93 +
  0.000.000.000.001536/1537Array#join93 +
  0.000.000.000.006144/6144User#sessions90 +
  0.000.000.000.003072/3072User#attributes35 +
  0.000.000.000.001536/1536Array#reverse93 +
  0.000.000.000.001536/3072Hash#[]36 +
  0.000.000.000.001536/1536Array#sum93 +
  0.000.000.000.001536/1536Array#max93 +
  0.000.000.000.001536/1539Array#count93 +
  0.110.000.000.111/1Object#work89
52.34%0.00%0.110.000.000.111 + + Object#collect_stats_from_users + + 33
  0.110.010.000.101/3Array#each34 +
  0.010.000.000.003/6147Object#work73
  0.080.010.000.066144/6147Array#each
41.76%9.34%0.090.020.000.076147 + + Array#map + +
  0.060.030.000.038464/8464<Class::Date>#parse99 +
  0.000.000.000.008464/8464Date#iso8601 +
  0.000.000.000.001536/1536Class#new84 +
  0.000.000.000.008664/8664String#upcase +
  0.000.000.000.008464/8464String#to_i90 +
  0.000.000.000.001536/3072Hash#[]84 +
  0.060.030.000.038464/8464Array#map
26.58%12.48%0.060.030.000.038464 + + <Class::Date>#parse + +
  0.010.010.000.0016928/16928Regexp#match +
  0.010.010.000.008464/8464String#gsub! +
  0.000.000.000.008464/8464MatchData#begin +
  0.000.000.000.008464/8464String#[]= +
  0.000.000.000.008464/8464Integer#div +
  0.000.000.000.008464/8464MatchData#end +
  0.020.010.000.018464/8464Array#each
10.14%6.70%0.020.010.000.018464 + + Object#parse_session + + 23
  0.010.010.000.0042320/68464Array#[]25 +
  0.000.000.000.001/10001Object#work42
  0.020.020.000.0010000/10001Array#each
9.86%9.86%0.020.020.000.0010001 + + String#split + +
  0.010.010.000.0016928/16928<Class::Date>#parse
5.70%5.70%0.010.010.000.0016928 + + Regexp#match + +
  0.000.000.000.006144/68464Object#parse_user16
  0.000.000.000.0020000/68464Array#each
  0.010.010.000.0042320/68464Object#parse_session25
5.66%5.66%0.010.010.000.0068464 + + Array#[] + +
  0.000.000.000.001/3073Object#work79
  0.010.000.000.003072/3073Array#each
3.58%2.23%0.010.000.000.003073 + + Array#sort + +
  0.000.000.000.0014789/14789Date#<=> +
  0.010.010.000.008464/8464<Class::Date>#parse
3.44%3.44%0.010.010.000.008464 + + String#gsub! + +
  0.010.000.000.011/1Object#work81
2.99%0.00%0.010.000.000.011 + + Enumerable#group_by + +
  0.010.010.000.001/3Array#each +
  0.000.000.000.008464/8464<Class::Date>#parse
2.17%2.17%0.000.000.000.008464 + + MatchData#begin + +
  0.000.000.000.008464/8464Array#map
2.08%2.08%0.000.000.000.008464 + + Date#iso8601 + +
  0.000.000.000.001536/1536Array#each
2.03%0.91%0.000.000.000.001536 + + Array#any? + +
  0.000.000.000.004492/6471String#=~97 +
  0.000.000.000.0020000/20000Array#each
1.99%1.99%0.000.000.000.0020000 + + String#== + +
  0.000.000.000.001536/1536Array#map
1.62%1.33%0.000.000.000.001536 + + Class#new + +
  0.000.000.000.001536/1536User#initialize +
  0.000.000.000.001979/6471Array#all?
  0.000.000.000.004492/6471Array#any?
1.53%1.53%0.000.000.000.006471 + + String#=~ + +
  0.000.000.000.001536/1536Array#each
1.48%0.97%0.000.000.000.001536 + + Object#parse_user + + 14
  0.000.000.000.006144/68464Array#[]16 +
  0.000.000.000.0014789/14789Array#sort
1.35%1.35%0.000.000.000.0014789 + + Date#<=> + +
  0.000.000.000.001/1Object#work103
1.34%1.34%0.000.000.000.001 + + JSON::Ext::Generator::GeneratorMethods::Hash#to_json + +
  0.000.000.000.001/1JSON::Ext::Generator::State#initialize +
  0.000.000.000.008464/8464<Class::Date>#parse
1.26%1.26%0.000.000.000.008464 + + String#[]= + +
  0.000.000.000.0010000/10000Array#each
1.20%1.20%0.000.000.000.0010000 + + Array#<< + +
  0.000.000.000.008664/8664Array#map
1.02%1.02%0.000.000.000.008664 + + String#upcase + +
  0.000.000.000.001/3073Object#work70
  0.000.000.000.003072/3073Array#each
0.99%0.99%0.000.000.000.003073 + + Hash#[]= + +
  0.000.000.000.008464/8464Array#map
0.88%0.88%0.000.000.000.008464 + + String#to_i + +
  0.000.000.000.001536/1536Array#each
0.85%0.44%0.000.000.000.001536 + + Array#all? + +
  0.000.000.000.001979/6471String#=~98 +
  0.000.000.000.008464/8464<Class::Date>#parse
0.83%0.83%0.000.000.000.008464 + + Integer#div + +
  0.000.000.000.008464/8464<Class::Date>#parse
0.71%0.71%0.000.000.000.008464 + + MatchData#end + +
  0.000.000.000.001/1Object#work73
0.69%0.69%0.000.000.000.001 + + Array#uniq + +
  0.000.000.000.001/1Object#work103
0.68%0.68%0.000.000.000.001 + + <Class::IO>#write + +
  0.000.000.000.001/1537Object#work79
  0.000.000.000.001536/1537Array#each
0.65%0.65%0.000.000.000.001537 + + Array#join + +
  0.000.000.000.006144/6144Array#each
0.49%0.49%0.000.000.000.006144 + + User#sessions + +
  0.000.000.000.001536/3072Array#each
  0.000.000.000.001536/3072Array#map
0.45%0.45%0.000.000.000.003072 + + Hash#[] + +
  0.000.000.000.001536/1536Class#new
0.29%0.29%0.000.000.000.001536 + + User#initialize + + 8
  0.000.000.000.003072/3072Array#each
0.28%0.28%0.000.000.000.003072 + + User#attributes + +
  0.000.000.000.001536/1536Array#each
0.24%0.24%0.000.000.000.001536 + + Array#reverse + +
  0.000.000.000.001536/1536Array#each
0.18%0.18%0.000.000.000.001536 + + Array#sum + +
  0.000.000.000.001536/1536Array#each
0.16%0.16%0.000.000.000.001536 + + Array#max + +
  0.000.000.000.003/1539Object#work70
  0.000.000.000.001536/1539Array#each
0.15%0.15%0.000.000.000.001539 + + Array#count + +
  0.000.000.000.001/1Object#work42
0.11%0.11%0.000.000.000.001 + + <Class::IO>#read + +
  0.000.000.000.001/1JSON::Ext::Generator::GeneratorMethods::Hash#to_json
0.00%0.00%0.000.000.000.001 + + JSON::Ext::Generator::State#initialize + +
* indicates recursively called methods
+ +
+ + + + diff --git a/ruby_prof_reports/graph_start.html b/ruby_prof_reports/graph_start.html new file mode 100644 index 00000000..81492b64 --- /dev/null +++ b/ruby_prof_reports/graph_start.html @@ -0,0 +1,3359 @@ + + + + + + +
+
+
+
Profile Report
+

Wall_time

+
+
+
Sunday, October 15 at 2:43:02 PM (+05)
+ +
+
+
+
+ + + + + + + + + + + + + +
Thread IDFiber IDTotal
2602407.726320823996502
+ + + +

Thread 260, Fiber: 240

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
%Total%SelfTotalSelfWaitChildCallsNameLine
100.00%0.00%7.730.000.007.731 + + [global]# + + 7
  7.730.000.007.731/1Object#work7 +
  7.730.000.007.731/1[global]#7
100.00%0.00%7.730.000.007.731 + + Object#work + + 45
  7.520.040.007.483/10Array#each51 +
  0.190.000.000.197/7Object#collect_stats_from_users108 +
  0.010.000.000.002/16898Array#map87 +
  0.000.000.000.001/1JSON::Ext::Generator::GeneratorMethods::Hash#to_json142 +
  0.000.000.000.001/20001String#split46 +
  0.000.000.000.001/3073Array#sort87 +
  0.000.000.000.001/1<Class::IO>#write142 +
  0.000.000.000.001/1Array#uniq87 +
  0.000.000.000.001/1<Class::IO>#read46 +
  0.000.000.000.001/1537Array#join87 +
  0.000.000.000.003/1539Array#count74 +
  0.000.000.000.001/12289Hash#[]=74 +
  0.190.040.000.157/10Object#collect_stats_from_users38
  7.520.040.007.483/10Object#work51
99.80%1.05%7.710.080.007.6310 + + Array#each + +
  6.754.940.001.811536/1536Array#select100 +
  0.600.260.000.3410000/10000Array#all?80 +
  0.100.040.000.0616896/16898Array#map114 +
  0.060.060.000.0011736/11736Array#+53 +
  0.030.010.000.028464/8464Object#parse_session54 +
  0.020.020.000.0010000/20001String#split52 +
  0.010.010.000.0024576/24576String#+39 +
  0.010.010.000.001536/1536Class#new101 +
  0.010.000.000.003072/3073Array#sort124 +
  0.010.000.000.001536/1536Object#parse_user53 +
  0.010.010.000.0021504/21504Hash#[]40 +
  0.010.010.000.0010752/10752Hash#merge109 +
  0.010.000.000.001536/1536Array#any?129 +
  0.010.010.000.0012288/12289Hash#[]=40 +
  0.000.000.000.0020000/13861980String#==53 +
  0.000.000.000.0021504/21504User#attributes39 +
  0.000.000.000.0020000/68464Array#[]53 +
  0.000.000.000.0010752/10752User#sessions109 +
  0.000.000.000.001536/1537Array#join124 +
  0.000.000.000.003072/3072Integer#to_s114 +
  0.000.000.000.001536/1536Array#reverse139 +
  0.000.000.000.001536/1536Array#sum114 +
  0.000.000.000.001536/1536Array#max119 +
  0.000.000.000.001536/1539Array#count109 +
  6.754.940.001.811536/1536Array#each
87.39%63.97%6.754.940.001.811536 + + Array#select + +
  1.811.810.000.0013000704/13861980String#==100 +
  0.000.000.000.0020000/13861980Array#each
  0.120.120.000.00841276/13861980BasicObject#!=
  1.811.810.000.0013000704/13861980Array#select
25.03%25.03%1.931.930.000.0013861980 + + String#== + +
  0.600.260.000.3410000/10000Array#each
7.74%3.30%0.600.260.000.3410000 + + Array#all? + +
  0.340.220.000.12841276/841276BasicObject#!=80 +
  0.000.000.000.001979/6471String#=~134 +
  0.000.000.000.001979/23399String#upcase134 +
  0.340.220.000.12841276/841276Array#all?
4.42%2.85%0.340.220.000.12841276 + + BasicObject#!= + +
  0.120.120.000.00841276/13861980String#== +
  0.190.000.000.197/7Object#work108
2.45%0.00%0.190.000.000.197 + + Object#collect_stats_from_users + + 37
  0.190.040.000.157/10Array#each38 +
  0.010.000.000.002/16898Object#work87
  0.100.040.000.0616896/16898Array#each
1.35%0.51%0.100.040.000.0616898 + + Array#map + +
  0.050.030.000.038464/8464<Class::Date>#parse139 +
  0.000.000.000.008464/8464Date#iso8601139 +
  0.000.000.000.0016928/23399String#upcase90 +
  0.000.000.000.0016928/16928String#to_i114 +
  0.060.060.000.0011736/11736Array#each
0.74%0.74%0.060.060.000.0011736 + + Array#+ + +
  0.050.030.000.038464/8464Array#map
0.68%0.34%0.050.030.000.038464 + + <Class::Date>#parse + +
  0.010.010.000.0016928/16928Regexp#match +
  0.010.010.000.008464/8464String#gsub! +
  0.000.000.000.008464/8464MatchData#begin +
  0.000.000.000.008464/8464String#[]= +
  0.000.000.000.008464/8464Integer#div +
  0.000.000.000.008464/8464MatchData#end +
  0.000.000.000.001/20001Object#work46
  0.000.000.000.001536/20001Object#parse_user17
  0.020.020.000.008464/20001Object#parse_session27
  0.020.020.000.0010000/20001Array#each
0.52%0.52%0.040.040.000.0020001 + + String#split + +
  0.030.010.000.028464/8464Array#each
0.45%0.18%0.030.010.000.028464 + + Object#parse_session + + 26
  0.020.020.000.008464/20001String#split27 +
  0.010.010.000.0042320/68464Array#[]29 +
  0.010.010.000.0024576/24576Array#each
0.13%0.13%0.010.010.000.0024576 + + String#+ + +
  0.000.000.000.006144/68464Object#parse_user19
  0.000.000.000.0020000/68464Array#each
  0.010.010.000.0042320/68464Object#parse_session29
0.12%0.12%0.010.010.000.0068464 + + Array#[] + +
  0.010.010.000.0016928/16928<Class::Date>#parse
0.12%0.12%0.010.010.000.0016928 + + Regexp#match + +
  0.000.000.000.001/3073Object#work87
  0.010.000.000.003072/3073Array#each
0.11%0.08%0.010.010.000.003073 + + Array#sort + +
  0.000.000.000.0014789/14789Date#<=> +
  0.010.010.000.001536/1536Array#each
0.10%0.08%0.010.010.000.001536 + + Class#new + +
  0.000.000.000.001536/1536User#initialize +
  0.010.010.000.008464/8464<Class::Date>#parse
0.09%0.09%0.010.010.000.008464 + + String#gsub! + +
  0.010.000.000.001536/1536Array#each
0.09%0.05%0.010.000.000.001536 + + Object#parse_user + + 16
  0.000.000.000.001536/20001String#split17 +
  0.000.000.000.006144/68464Array#[]19 +
  0.010.010.000.0021504/21504Array#each
0.07%0.07%0.010.010.000.0021504 + + Hash#[] + +
  0.010.010.000.0010752/10752Array#each
0.07%0.07%0.010.010.000.0010752 + + Hash#merge + +
  0.000.000.000.001979/23399Array#all?
  0.000.000.000.004492/23399Array#any?
  0.000.000.000.0016928/23399Array#map
0.07%0.07%0.010.010.000.0023399 + + String#upcase + +
  0.010.000.000.001536/1536Array#each
0.07%0.03%0.010.000.000.001536 + + Array#any? + +
  0.000.000.000.004492/6471String#=~129 +
  0.000.000.000.004492/23399String#upcase129 +
  0.000.000.000.001/12289Object#work74
  0.010.010.000.0012288/12289Array#each
0.07%0.07%0.010.010.000.0012289 + + Hash#[]= + +
  0.000.000.000.008464/8464Array#map
0.06%0.06%0.000.000.000.008464 + + Date#iso8601 + +
  0.000.000.000.008464/8464<Class::Date>#parse
0.06%0.06%0.000.000.000.008464 + + MatchData#begin + +
  0.000.000.000.0021504/21504Array#each
0.04%0.04%0.000.000.000.0021504 + + User#attributes + +
  0.000.000.000.0016928/16928Array#map
0.04%0.04%0.000.000.000.0016928 + + String#to_i + +
  0.000.000.000.001/1Object#work142
0.04%0.04%0.000.000.000.001 + + JSON::Ext::Generator::GeneratorMethods::Hash#to_json + +
  0.000.000.000.001/1JSON::Ext::Generator::State#initialize +
  0.000.000.000.001979/6471Array#all?
  0.000.000.000.004492/6471Array#any?
0.04%0.04%0.000.000.000.006471 + + String#=~ + +
  0.000.000.000.0014789/14789Array#sort
0.04%0.04%0.000.000.000.0014789 + + Date#<=> + +
  0.000.000.000.008464/8464<Class::Date>#parse
0.03%0.03%0.000.000.000.008464 + + String#[]= + +
  0.000.000.000.001536/1536Class#new
0.03%0.03%0.000.000.000.001536 + + User#initialize + + 10
  0.000.000.000.0010752/10752Array#each
0.03%0.03%0.000.000.000.0010752 + + User#sessions + +
  0.000.000.000.008464/8464<Class::Date>#parse
0.02%0.02%0.000.000.000.008464 + + Integer#div + +
  0.000.000.000.008464/8464<Class::Date>#parse
0.02%0.02%0.000.000.000.008464 + + MatchData#end + +
  0.000.000.000.001/1Object#work142
0.02%0.02%0.000.000.000.001 + + <Class::IO>#write + +
  0.000.000.000.001/1537Object#work87
  0.000.000.000.001536/1537Array#each
0.01%0.01%0.000.000.000.001537 + + Array#join + +
  0.000.000.000.003072/3072Array#each
0.01%0.01%0.000.000.000.003072 + + Integer#to_s + +
  0.000.000.000.001/1Object#work87
0.01%0.01%0.000.000.000.001 + + Array#uniq + +
  0.000.000.000.001536/1536Array#each
0.00%0.00%0.000.000.000.001536 + + Array#reverse + +
  0.000.000.000.001536/1536Array#each
0.00%0.00%0.000.000.000.001536 + + Array#sum + +
  0.000.000.000.001536/1536Array#each
0.00%0.00%0.000.000.000.001536 + + Array#max + +
  0.000.000.000.001/1Object#work46
0.00%0.00%0.000.000.000.001 + + <Class::IO>#read + +
  0.000.000.000.003/1539Object#work74
  0.000.000.000.001536/1539Array#each
0.00%0.00%0.000.000.000.001539 + + Array#count + +
  0.000.000.000.001/1JSON::Ext::Generator::GeneratorMethods::Hash#to_json
0.00%0.00%0.000.000.000.001 + + JSON::Ext::Generator::State#initialize + +
* indicates recursively called methods
+ +
+ + + + diff --git a/stackprof_reports/stackprof.dump b/stackprof_reports/stackprof.dump new file mode 100644 index 0000000000000000000000000000000000000000..8e77d91a1b96ef935a3523ce7a526f8fd5c8273b GIT binary patch literal 2703 zcmbVOOK%%h6!y4P;&JTQPC_54Xw$e7MQ!2)5TfI>1o23N)TU2VsUUOXT-zrZd(7NP znI@T!E6_yHg!R?sd=TlfPk03pE!!6IUT_|CoK&IER7B%d>P&f`0e zdycoJx>+Z4LHdfkRxLF>`G{jTy(Q_`Yr=J%EVTmZUl1-Of7#+>lxVhHsVG?+c5?M< zrT1=Kb%vXylw7)hwA;xxWgwPBAi4=>pyrFFRNaT%1F80nFMhxCS~u<3Eu4*K<`*V? zDV7|&MlN1wsGU!Y*QZ_+41LZFp?<`j^`H^mt{35u6h1S zIX6FkwAApLvb3tCUuydve^Vu|9Z-`li2z}id_k_7h#yS^Laj`f_;+G@(qHUz`kp;g z&eNmi0wsSOg45);Stl)*>Ih==eh?Z;XOyAP9-QX4e2&m4X%FFL>V5sP3+%cPNrCPB z!O@d-9sCb}8~z&j6CY{m4A|L(W^-T@8(M-RZW!U@dLAz~?`e@i>eCPs#=dn6pRU}{ zpZdX`voy=v>&9&s>{s7>$p}t@?aXP`20QEB<|tTp<74eK<)pa;s=JRKJKqma37P@5 zE>nXJG4m--956-7QW-Qy89EG_!gGcN-hsdi%-o|nItvD9sREj&etH>n2m(T%CulLG z%b-d1ASJ)gP=oo~c}T5*djR%b(A{`^&;gvUfo=!wfM&_2%b*4Le-(5D=N2T)ZcWZK=@-Us(Lg}*|r`orbicmmokf^ey?o5shT`|HAA6m>aP^;{R%6n7JH zvoAuOT5LyQzY3`&R4?Dy0&=$Uu6(to< zI%wpP*fDt81C=}+aT>xaJA#Dv(_X~FEi?|AC%$#&dh4|2p7MQhu_#5g5qVF3$2A)G zSBCZ%;^a{JYqlx>q49q|}cIY=`rH1utopz}Zrac=|e6y!NUG2Hzc_YUCY zi?$uKU$=vqIdR;W?N3Iyt?RILDzp{0)*PUi`K0v*O}tIfj;URP+V0J23TkGQ=`x}F zbeUG$RiR|0nt^6C>f*?h=f~=qgIqTBaOJojR^0w(ENTy7Ay!-TN@TvbCCtp!<_jhO zCArZeNsLptNZ#GDIgI38MrWq1iT`O=C{=99wMcgmnp|wI!0ax)1bD(5R%?x%Ma_!T zqJXeMFL466?ebyyQu^W+P$!H`4oi=5UHW}t>BE~*!DI+jrRICh3ip8uEgj&iatk=7 zfP+nh8%S@0ji2=#=b0ZC)p{2mZJLC~9G-)q)-AO71ej4gB|i9s3eYghCdEgEY80E& zug5Bwg;Ta{){U0Shs6%O3PoA!hhVgf;x$|LC^nFKH8Yzk-V&m9G1jc?n8zSzJq%0Z z(A}ZUXP*&)EY2LpH118i9*B+icq3}5-UO+u)y2J$_S&A<&YCo fields[1], 'first_name' => fields[2], 'last_name' => fields[3], - 'age' => fields[4], + 'age' => fields[4] } end -def parse_session(session) - fields = session.split(',') - parsed_result = { +def parse_session(fields) + { 'user_id' => fields[1], 'session_id' => fields[2], 'browser' => fields[3], 'time' => fields[4], - 'date' => fields[5], + 'date' => fields[5] } end def collect_stats_from_users(report, users_objects, &block) users_objects.each do |user| - user_key = "#{user.attributes['first_name']}" + ' ' + "#{user.attributes['last_name']}" + user_key = "#{user.attributes['first_name']} #{user.attributes['last_name']}" report['usersStats'][user_key] ||= {} - report['usersStats'][user_key] = report['usersStats'][user_key].merge(block.call(user)) + report['usersStats'][user_key] = block.call(user) end end -def work - file_lines = File.read('data.txt').split("\n") +def work(file = 'data.txt') + collect_stats(File.read(file).split("\n")) +end +def collect_stats(file_lines) users = [] sessions = [] file_lines.each do |line| cols = line.split(',') - users = users + [parse_user(line)] if cols[0] == 'user' - sessions = sessions + [parse_session(line)] if cols[0] == 'session' + users << parse_user(cols) if cols[0] == 'user' + sessions << parse_session(cols) if cols[0] == 'session' end # Отчёт в json @@ -75,102 +73,31 @@ def work report[:totalUsers] = users.count # Подсчёт количества уникальных браузеров - uniqueBrowsers = [] - sessions.each do |session| - browser = session['browser'] - uniqueBrowsers += [browser] if uniqueBrowsers.all? { |b| b != browser } - end - - report['uniqueBrowsersCount'] = uniqueBrowsers.count - + unique_browsers = sessions.map { |session| session['browser'].upcase }.uniq + report['uniqueBrowsersCount'] = unique_browsers.count report['totalSessions'] = sessions.count - - report['allBrowsers'] = - sessions - .map { |s| s['browser'] } - .map { |b| b.upcase } - .sort - .uniq - .join(',') + report['allBrowsers'] = unique_browsers.sort.join(',') # Статистика по пользователям - users_objects = [] - - users.each do |user| - attributes = user - user_sessions = sessions.select { |session| session['user_id'] == user['id'] } - user_object = User.new(attributes: attributes, sessions: user_sessions) - users_objects = users_objects + [user_object] - end + sessions_by_users = sessions.group_by { |session| session['user_id'] } + users_objects = users.map { |user| User.new(attributes: user, sessions: sessions_by_users[user['id']] || []) } report['usersStats'] = {} # Собираем количество сессий по пользователям collect_stats_from_users(report, users_objects) do |user| - { 'sessionsCount' => user.sessions.count } - end - - # Собираем количество времени по пользователям - collect_stats_from_users(report, users_objects) do |user| - { 'totalTime' => user.sessions.map {|s| s['time']}.map {|t| t.to_i}.sum.to_s + ' min.' } - end - - # Выбираем самую длинную сессию пользователя - collect_stats_from_users(report, users_objects) do |user| - { 'longestSession' => user.sessions.map {|s| s['time']}.map {|t| t.to_i}.max.to_s + ' min.' } - end - - # Браузеры пользователя через запятую - collect_stats_from_users(report, users_objects) do |user| - { 'browsers' => user.sessions.map {|s| s['browser']}.map {|b| b.upcase}.sort.join(', ') } - end - - # Хоть раз использовал IE? - collect_stats_from_users(report, users_objects) do |user| - { 'usedIE' => user.sessions.map{|s| s['browser']}.any? { |b| b.upcase =~ /INTERNET EXPLORER/ } } - end - - # Всегда использовал только Chrome? - collect_stats_from_users(report, users_objects) do |user| - { 'alwaysUsedChrome' => user.sessions.map{|s| s['browser']}.all? { |b| b.upcase =~ /CHROME/ } } - end - - # Даты сессий через запятую в обратном порядке в формате iso8601 - collect_stats_from_users(report, users_objects) do |user| - { 'dates' => user.sessions.map{|s| s['date']}.map {|d| Date.parse(d)}.sort.reverse.map { |d| d.iso8601 } } + session_time_list = user.sessions.map { |s| s['time'].to_i } + session_brouser_list = user.sessions.map { |s| s['browser'].upcase } + { + 'sessionsCount' => user.sessions.count, + 'totalTime' => "#{session_time_list.sum} min.", + 'longestSession' => "#{session_time_list.max} min.", + 'browsers' => session_brouser_list.sort.join(', '), + 'usedIE' => session_brouser_list.any? { |browser| browser =~ /INTERNET EXPLORER/ }, + 'alwaysUsedChrome' => session_brouser_list.all? { |browser| browser =~ /CHROME/ }, + 'dates' => user.sessions.map { |s| Date.parse(s['date']) }.sort.reverse.map(&:iso8601) + } end File.write('result.json', "#{report.to_json}\n") end - -class TestMe < Minitest::Test - def setup - File.write('result.json', '') - File.write('data.txt', -'user,0,Leida,Cira,0 -session,0,0,Safari 29,87,2016-10-23 -session,0,1,Firefox 12,118,2017-02-27 -session,0,2,Internet Explorer 28,31,2017-03-28 -session,0,3,Internet Explorer 28,109,2016-09-15 -session,0,4,Safari 39,104,2017-09-27 -session,0,5,Internet Explorer 35,6,2016-09-01 -user,1,Palmer,Katrina,65 -session,1,0,Safari 17,12,2016-10-21 -session,1,1,Firefox 32,3,2016-12-20 -session,1,2,Chrome 6,59,2016-11-11 -session,1,3,Internet Explorer 10,28,2017-04-29 -session,1,4,Chrome 13,116,2016-12-28 -user,2,Gregory,Santos,86 -session,2,0,Chrome 35,6,2018-09-21 -session,2,1,Safari 49,85,2017-05-22 -session,2,2,Firefox 47,17,2018-02-02 -session,2,3,Chrome 20,84,2016-11-25 -') - end - - def test_result - work - expected_result = '{"totalUsers":3,"uniqueBrowsersCount":14,"totalSessions":15,"allBrowsers":"CHROME 13,CHROME 20,CHROME 35,CHROME 6,FIREFOX 12,FIREFOX 32,FIREFOX 47,INTERNET EXPLORER 10,INTERNET EXPLORER 28,INTERNET EXPLORER 35,SAFARI 17,SAFARI 29,SAFARI 39,SAFARI 49","usersStats":{"Leida Cira":{"sessionsCount":6,"totalTime":"455 min.","longestSession":"118 min.","browsers":"FIREFOX 12, INTERNET EXPLORER 28, INTERNET EXPLORER 28, INTERNET EXPLORER 35, SAFARI 29, SAFARI 39","usedIE":true,"alwaysUsedChrome":false,"dates":["2017-09-27","2017-03-28","2017-02-27","2016-10-23","2016-09-15","2016-09-01"]},"Palmer Katrina":{"sessionsCount":5,"totalTime":"218 min.","longestSession":"116 min.","browsers":"CHROME 13, CHROME 6, FIREFOX 32, INTERNET EXPLORER 10, SAFARI 17","usedIE":true,"alwaysUsedChrome":false,"dates":["2017-04-29","2016-12-28","2016-12-20","2016-11-11","2016-10-21"]},"Gregory Santos":{"sessionsCount":4,"totalTime":"192 min.","longestSession":"85 min.","browsers":"CHROME 20, CHROME 35, FIREFOX 47, SAFARI 49","usedIE":false,"alwaysUsedChrome":false,"dates":["2018-09-21","2018-02-02","2017-05-22","2016-11-25"]}}}' + "\n" - assert_equal expected_result, File.read('result.json') - end -end diff --git a/test_me.rb b/test_me.rb new file mode 100644 index 00000000..5736bf18 --- /dev/null +++ b/test_me.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'minitest/autorun' +require_relative 'task-1' + +class TestMe < Minitest::Test + def setup + File.write('result.json', '') + File.write('data.txt', +'user,0,Leida,Cira,0 +session,0,0,Safari 29,87,2016-10-23 +session,0,1,Firefox 12,118,2017-02-27 +session,0,2,Internet Explorer 28,31,2017-03-28 +session,0,3,Internet Explorer 28,109,2016-09-15 +session,0,4,Safari 39,104,2017-09-27 +session,0,5,Internet Explorer 35,6,2016-09-01 +user,1,Palmer,Katrina,65 +session,1,0,Safari 17,12,2016-10-21 +session,1,1,Firefox 32,3,2016-12-20 +session,1,2,Chrome 6,59,2016-11-11 +session,1,3,Internet Explorer 10,28,2017-04-29 +session,1,4,Chrome 13,116,2016-12-28 +user,2,Gregory,Santos,86 +session,2,0,Chrome 35,6,2018-09-21 +session,2,1,Safari 49,85,2017-05-22 +session,2,2,Firefox 47,17,2018-02-02 +session,2,3,Chrome 20,84,2016-11-25 +') + end + + def test_result + work + expected_result = '{"totalUsers":3,"uniqueBrowsersCount":14,"totalSessions":15,"allBrowsers":"CHROME 13,CHROME 20,CHROME 35,CHROME 6,FIREFOX 12,FIREFOX 32,FIREFOX 47,INTERNET EXPLORER 10,INTERNET EXPLORER 28,INTERNET EXPLORER 35,SAFARI 17,SAFARI 29,SAFARI 39,SAFARI 49","usersStats":{"Leida Cira":{"sessionsCount":6,"totalTime":"455 min.","longestSession":"118 min.","browsers":"FIREFOX 12, INTERNET EXPLORER 28, INTERNET EXPLORER 28, INTERNET EXPLORER 35, SAFARI 29, SAFARI 39","usedIE":true,"alwaysUsedChrome":false,"dates":["2017-09-27","2017-03-28","2017-02-27","2016-10-23","2016-09-15","2016-09-01"]},"Palmer Katrina":{"sessionsCount":5,"totalTime":"218 min.","longestSession":"116 min.","browsers":"CHROME 13, CHROME 6, FIREFOX 32, INTERNET EXPLORER 10, SAFARI 17","usedIE":true,"alwaysUsedChrome":false,"dates":["2017-04-29","2016-12-28","2016-12-20","2016-11-11","2016-10-21"]},"Gregory Santos":{"sessionsCount":4,"totalTime":"192 min.","longestSession":"85 min.","browsers":"CHROME 20, CHROME 35, FIREFOX 47, SAFARI 49","usedIE":false,"alwaysUsedChrome":false,"dates":["2018-09-21","2018-02-02","2017-05-22","2016-11-25"]}}}' + "\n" + assert_equal expected_result, File.read('result.json') + end +end