Ubiregi Advent Calendar 2018 ã® 18 æ¥ç®ã§ãã
ã¦ãã¬ã¸ã§ã¯ããããã®ã客æ§ã®å¤§éã® POS ãã¼ã¿ããé ãããã¦ãããæ§ã ãªãããå¦çãå®è¡ããã¦ãã¾ããä»åã¯ç¹å®ã®ã±ã¼ã¹ã§ãããå¦çã®ä¸é¨ã 30 å以ä¸ããã£ã¦ããå¦çã 14 ç§ã§çµããããã«ãã話ã«ã¤ãã¦æ¸ãããã¨æãã¾ããååã® Ruby 2.5 の SEGV と闘った話 - @watson1978 の日記 ã«å¼ãç¶ã DTrace ã使ã£ã話ã«ãªãã¾ãã
ã¯ããã«
ã¦ãã¬ã¸ã§ã¯ CSV ãã¡ã¤ã«ã§ã客æ§ãç¹å®ã®ãã¼ã¿ããã¦ã³ãã¼ããããã¢ãããã¼ãã§ããæ©è½ãããã¾ããCSV ãã¡ã¤ã«ã«ã¨ã¯ã¹ãã¼ãããããCSV ãã¡ã¤ã«ãã DB ã«åãè¾¼ãå¦çã Worker ãèµ·åãã¦ãããå¦çãã¦ãã¾ãã
大éã®ãã¼ã¿ãä¿æãã¦ããã¢ã«ã¦ã³ãã¨åéã®ãã¼ã¿ãç¨æãã¦æå ã®ç°å¢ã§è©¦ããã¨ããæéãããããã¨ãçºè¦ãã¾ãããRails ã®ãã°ããªããã¦ãã¦ã DB ã«ã¢ã¯ã»ã¹ãã¦ããé°å²æ°ãç¡ããå é¨å¦çã§ä½ãè©°ã¾ã£ã¦ããã®ãã¨ç¾è±¡ã追ãããã¦ã¿ã¾ããã
DTrace ãæå¹ã«ãã
rbenv
㧠Ruby ãã¤ã³ã¹ãã¼ã«ããéã«ã以ä¸ã®æ§ã«ãªãã·ã§ã³ãæå®ãã㨠macOS ä¸ã§ Ruby ã® DTrace æ©è½ãæå¹ã«ãªãã¾ãã
$ CONFIGURE_OPTS="--enable-dtrace" rbenv install 2.5.3
DTrace ã使ãã¨ç¨¼åä¸ã®ã·ã¹ãã ã«æãå ãããã¨ç¡ãæ¯ãèãã追跡ãããã¨ãã§ãã¨ã¦ã便å©ã§ãã
è¨æ¸¬ãã
以ä¸ã® DTrace ã®ã¹ã¯ãªããã§ããããå¦çä¸ã«å Ruby ã¡ã½ãããå¼ã³åºããåæ°ã¨å®è¡æéãè¨æ¸¬ãã¾ããã
#!/usr/sbin/dtrace -s #pragma D option quiet ruby$target:::method-entry { @method_call_count[copyinstr(arg0), copyinstr(arg1)] = count(); self->method_starttime = walltimestamp / 1000; } ruby$target:::cmethod-entry { @method_call_count[copyinstr(arg0), copyinstr(arg1)] = count(); self->cmethod_starttime = walltimestamp / 1000; } ruby$target:::method-return { @invoked_time[copyinstr(arg0), copyinstr(arg1)] = sum((walltimestamp / 1000) - self->method_starttime); } ruby$target:::cmethod-return { @invoked_time[copyinstr(arg0), copyinstr(arg1)] = sum((walltimestamp / 1000) - self->cmethod_starttime); } END { printf("\n"); printf("%-30s %-15s %s\n", "CLASS", "METHOD", "COUNT"); printf("--------------------------------------------------------------------------------\n"); printa("%-30s %-15s %@d\n", @method_call_count); printf("\n"); printf("%-30s %-15s %s\n", "CLASS", "METHOD", "TOTAL TIME usec"); printf("--------------------------------------------------------------------------------\n"); printa("%-30s %-15s %@d\n", @invoked_time); }
ãã®ã¹ã¯ãªãã㯠DTrace ã§è¨æ¸¬ãããããã»ã¹ãçµäºããããè¨æ¸¬ã CTRL
+ C
ã§ä¸æããã¾ã§è¨æ¸¬ãç¶ãã¾ããå®è¡ããçµæã以ä¸ã®æ§ãªãã°ã«ãªãã¾ãï¼æ°åç¨åº¦ã§ä¸æãã¾ãããï¼ã
$ sudo dtrace -q -s measure.d -p [Worker ã®ããã»ã¹ ID] CLASS METHOD COUNT -------------------------------------------------------------------------------- #<Class:0x00007fe014884108> lambda 424 #<Class:0x00007fe01db2a9d0> category 424 #<Class:0x00007fe01db2a9d0> name 424 #<Class:0x00007fe01db2a9d0> new 424 Array compact 424 Array include? 424 Array select 424 Array zip 424 BigDecimal initialize 424 BigDecimal new 424 Class new 424 Enumerable all? 424 Kernel method 424 Method to_proc 424 Regexp === 424 String gsub! 424 String rstrip! 424 String sub! 424 #<Class:0x00007fe01db2a9d0> group 425 #<Class:0x00007fe01db2a9d0> item_type 848 Integer === 848 #<Class:0x00007fe01db2a9d0> vat 1272 Array each 1272 Array map 1272 #<Class:0x00007fe01db2a9d0> price 1696 #<Class:0x00007fe01db2a9d0> sku 1696 Array first 1696 Kernel public_send 1696 Kernel respond_to? 1696 String strip 1696 Regexp match? 2120 Struct []= 4240 Symbol =~ 4240 CLASS METHOD TOTAL TIME usec -------------------------------------------------------------------------------- Array compact 1617 String rstrip! 1727 Kernel method 2196 String gsub! 2790 Integer === 2829 BigDecimal initialize 2844 Array zip 2861 String sub! 3295 Regexp === 3980 Class new 4410 Array select 4515 Array first 5171 Kernel respond_to? 5820 BigDecimal new 6126 Enumerable all? 6158 String strip 6200 Array map 6604 Array each 8555 Regexp match? 11051 Kernel public_send 12027 Struct []= 13245 Symbol =~ 16732 #<Class:0x00007fe01db2a9d0> category 533850 #<Class:0x00007fe01db2a9d0> new 537748 #<Class:0x00007fe01db2a9d0> name 540244 #<Class:0x00007fe014884108> lambda 547411 Method to_proc 549701 #<Class:0x00007fe01db2a9d0> group 604678 #<Class:0x00007fe01db2a9d0> item_type 1076239 #<Class:0x00007fe01db2a9d0> vat 1599474 #<Class:0x00007fe01db2a9d0> sku 2143290 #<Class:0x00007fe01db2a9d0> price 2152747 Array include? 1544897529611642
ãã®ãã°ãã Array#include?
ã 424 åããå¼ã³åºãã¦ããªãã®ã«ãæ¡éãã«å®è¡æéãé·ããã¨ããããã¾ããã
Array#include? ãã©ãã§å®è¡ãã¦ããï¼
ããã§å¥ã®ã¹ã¯ãªãããç¨æãã¾ãããArray#include?
㯠C è¨èªã§å®è£
ããã¦ããã®ã§ cmethod-entry
ã¨ããããã¼ãã§è£è¶³ã§ãã¾ãã以ä¸ã®ã¹ã¯ãªããã§ã¯ Array#include?
ã®ã¨ãã ã cmethod-entry
ãå®è¡ãããããã«ãã¦ããã¾ããArray#include?
ãå¼ã³åºãããéã«ãå¼ã³åºãããã¡ã¤ã«åã¨è¡çªå·ãåºåãã¦ãã¾ãã
#!/usr/sbin/dtrace -s #pragma D option quiet // ruby:::cmethod-entry(classname, methodname, filename, lineno); ruby$target:::cmethod-entry / copyinstr(arg0) == "Array" && copyinstr(arg1) == "include?" / { printf("%s : %d\n", copyinstr(arg2), arg3); }
å®è¡ããã¨ä»¥ä¸ã®æ§ã«ãã©ã®ãã¡ã¤ã«ã®ä½è¡ç®ã§å¼ã³åºããã¦ããããããã¾ããã
$ sudo dtrace -q -s trace.d -p [Worker ã®ããã»ã¹ ID] /Users/watson/src/ubiregi-server/lib/menu_import/menu_reader.rb : 60 /Users/watson/src/ubiregi-server/lib/menu_import/menu_reader.rb : 60 /Users/watson/src/ubiregi-server/lib/menu_import/menu_reader.rb : 60 /Users/watson/src/ubiregi-server/lib/menu_import/menu_reader.rb : 60 ...(ç¥)...
ããã¾ã§ Ruby ã®ã³ã¼ãã«ä¸åæãå ããã«åå ç®æããããã¾ãããDTrace 便å©(\( â°ââ°)/)
åç¾ã³ã¼ãã¨ä¿®æ£å¾ã®ã³ã¼ã
該å½ç®æãè¦ãã¨ãããå¦çããããã¼ã¿ãã¦ãã¼ã¯ãªå¤ã«ãªã£ã¦ããªãã£ããä¾å¤ããããããã«ãªã£ã¦ãã¾ãããåç¾ããã¨ä»¥ä¸ã®æ§ãªã³ã¼ãã«ãªãã¾ãã
data = (1..200_000).to_a.map(&:to_s) array = [] data.each do |item| if array.include?(item) raise "item is not uniq" end array << item end
ãã§ãã¯ãããã¼ã¿ãé
åã§ä¿æããæ¯å Array#include?
ã§éè¤ãã¦ããªãã確èªãã¦ãã¾ãããArray#include?
ã§ã¯é
åã®åè¦ç´ ã®æååãä¸ã¤ãã¤æ¯è¼ãããã¨ã«ãªãã®ã§ãè¦ç´ ãå¤ããªãã°å½ç¶é
ããªãã¾ãã
Hash ã使ãã°ç°¡åã«ãã¼ã¿ã®åè¦ç´ ãã¦ãã¼ã¯ããã§ãã¯ã§ãããã ã£ãã®ã§ä»¥ä¸ã®æ§ã«ãã¾ããã
data = (1..200_000).to_a.map(&:to_s) hash = {} data.each do |item| if hash[item] raise "item is not uniq" end hash[item] = true end
該å½ç®æã®å¦çãã¡ããã¨è¨æ¸¬ããã¨ãä¿®æ£å㯠2091.88 sec
ããã£ã¦ããã®ã§ããä¿®æ£å¾ã«ã¯ 13.94 sec
ã¸å¤§å¹
ã«å¦çæéãæ¸ã£ã¦ãã¾ããã
ã¾ã¨ã
DTrace ã使ãã¨ã·ã¹ãã ã®æåããã£ãã調ã¹ãã¨ãã«ä¾¿å©ã§ãã