Skip to content

Conversation

@yui-knk
Copy link
Collaborator

@yui-knk yui-knk commented Mar 12, 2025

Pass StateItem to Triple.new so that the number of StateItem instance creation decreases.

Before:

$ stackprof tmp/stackprof-cpu-myapp.dump --method "Lrama::Counterexamples#shortest_path"
Lrama::Counterexamples#shortest_path (yui-knk/lrama/lib/lrama/counterexamples.rb:273)
  samples:  2752 self (21.5%)  /   4854 total (37.9%)
  callers:
    4854  (  100.0%)  Lrama::Counterexamples#reduce_reduce_examples
    3345  (   68.9%)  Hash#each_key
  callees (2102 total):
    3362  (  159.9%)  Set#each
     518  (   24.6%)  Lrama::Counterexamples::Triple#state_item
     256  (   12.2%)  Class#new
     251  (   11.9%)  Set#include?
     241  (   11.5%)  #<Class:0x0000000104f1b698>.new
     219  (   10.4%)  #<Class:0x0000000104f1c598>.new
     196  (    9.3%)  Lrama::Counterexamples#reachable_state_items
     128  (    6.1%)  Struct#hash
     107  (    5.1%)  Lrama::Counterexamples#follow_l
      65  (    3.1%)  Array#shift
      40  (    1.9%)  Struct#eql?
      27  (    1.3%)  Lrama::States::Item#next_sym
      18  (    0.9%)  Array#hash
      17  (    0.8%)  Array#eql?
       2  (    0.1%)  Lrama::State#==
  code:
                                  |   273  |     def shortest_path(conflict_state, conflict_reduce_item, conflict_term)
                                  |   274  |       queue = [] #: Array[[Triple, Array[Path::path]]]
                                  |   275  |       visited = {} #: Hash[Triple, true]
                                  |   276  |       start_state = @states.states.first #: Lrama::State
                                  |   277  |       conflict_term_bit = Bitmap::from_array([conflict_term.number])
                                  |   278  |       raise "BUG: Start state should be just one kernel." if start_state.kernels.count != 1
  196    (1.5%)                   |   279  |       reachable = reachable_state_items(StateItem.new(conflict_state, conflict_reduce_item))
                                  |   280  |       start = Triple.new(start_state, start_state.kernels.first, Bitmap::from_array([@states.eof_symbol.number]))
                                  |   281  |
                                  |   282  |       queue << [start, [StartPath.new(start.state_item)]]
                                  |   283  |
  104    (0.8%) /    39   (0.3%)  |   284  |       while (triple, paths = queue.shift)
  437    (3.4%) /   296   (2.3%)  |   285  |         next if visited[triple]
  190    (1.5%) /   175   (1.4%)  |   286  |         visited[triple] = true
                                  |   287  |
                                  |   288  |         # Found
    2    (0.0%)                   |   289  |         if (triple.state == conflict_state) && (triple.item == conflict_reduce_item) && (triple.l & conflict_term_bit != 0)
                                  |   290  |           return paths
                                  |   291  |         end
                                  |   292  |
                                  |   293  |         # transition
  150    (1.2%) /    57   (0.4%)  |   294  |         next_state_item = @transitions[[triple.state_item, triple.item.next_sym]]
   26    (0.2%) /     1   (0.0%)  |   295  |         if next_state_item && reachable.include?(next_state_item)
                                  |   296  |           # @type var t: Triple
   33    (0.3%) /     2   (0.0%)  |   297  |           t = Triple.new(next_state_item.state, next_state_item.item, triple.l)
  287    (2.2%) /   218   (1.7%)  |   298  |           queue << [t, paths + [TransitionPath.new(triple.state_item, t.state_item)]]
                                  |   299  |         end
                                  |   300  |
                                  |   301  |         # production step
 3431   (26.8%) /    26   (0.2%)  |   302  |         @productions[triple.state_item]&.each do |item|
  469    (3.7%) /    24   (0.2%)  |   303  |           next unless reachable.include?(StateItem.new(triple.state, item))
                                  |   304  |
  118    (0.9%) /    11   (0.1%)  |   305  |           l = follow_l(triple.item, triple.l)
                                  |   306  |           # @type var t: Triple
  222    (1.7%) /    12   (0.1%)  |   307  |           t = Triple.new(triple.state, item, l)
 2534   (19.8%) /  1891  (14.8%)  |   308  |           queue << [t, paths + [ProductionPath.new(triple.state_item, t.state_item)]]
                                  |   309  |         end

After:

$ stackprof tmp/stackprof-cpu-myapp.dump --method "Lrama::Counterexamples#shortest_path"
Lrama::Counterexamples#shortest_path (yui-knk/lrama/lib/lrama/counterexamples.rb:273)
  samples:  4512 self (34.3%)  /   7467 total (56.8%)
  callers:
    7467  (  100.0%)  Lrama::Counterexamples#reduce_reduce_examples
    6605  (   88.5%)  Hash#each_key
  callees (2955 total):
    6619  (  224.0%)  Set#each
    1136  (   38.4%)  Class#new
    1095  (   37.1%)  #<Class:0x00000001047f78a8>.new
     238  (    8.1%)  Lrama::Counterexamples#reachable_state_items
     216  (    7.3%)  Set#include?
     117  (    4.0%)  Kernel#hash
      43  (    1.5%)  Lrama::Counterexamples#follow_l
      35  (    1.2%)  Lrama::States::Item#next_sym
      16  (    0.5%)  Array#shift
      13  (    0.4%)  Lrama::Counterexamples::Triple#state
       8  (    0.3%)  Array#hash
       7  (    0.2%)  Array#eql?
       5  (    0.2%)  Struct#hash
       4  (    0.1%)  Lrama::Counterexamples::Triple#state_item
       3  (    0.1%)  Struct#eql?
       3  (    0.1%)  Lrama::Counterexamples::Triple#item
       2  (    0.1%)  Lrama::State#==
  code:
                                  |   273  |     def shortest_path(conflict_state, conflict_reduce_item, conflict_term)
                                  |   274  |       queue = [] #: Array[[Triple, Array[Path::path]]]
                                  |   275  |       visited = {} #: Hash[Triple, true]
                                  |   276  |       start_state = @states.states.first #: Lrama::State
                                  |   277  |       conflict_term_bit = Bitmap::from_array([conflict_term.number])
                                  |   278  |       raise "BUG: Start state should be just one kernel." if start_state.kernels.count != 1
  238    (1.8%)                   |   279  |       reachable = reachable_state_items(StateItem.new(conflict_state, conflict_reduce_item))
                                  |   280  |       start = Triple.new(StateItem.new(start_state, start_state.kernels.first), Bitmap::from_array([@states.eof_symbol.number]))
                                  |   281  |
                                  |   282  |       queue << [start, [StartPath.new(start.state_item)]]
                                  |   283  |
   21    (0.2%) /     5   (0.0%)  |   284  |       while (triple, paths = queue.shift)
  135    (1.0%) /    18   (0.1%)  |   285  |         next if visited[triple]
   77    (0.6%) /    77   (0.6%)  |   286  |         visited[triple] = true
                                  |   287  |
                                  |   288  |         # Found
    4    (0.0%) /     1   (0.0%)  |   289  |         if (triple.state == conflict_state) && (triple.item == conflict_reduce_item) && (triple.l & conflict_term_bit != 0)
                                  |   290  |           return paths
                                  |   291  |         end
                                  |   292  |
                                  |   293  |         # transition
   83    (0.6%) /    32   (0.2%)  |   294  |         next_state_item = @transitions[[triple.state_item, triple.item.next_sym]]
   17    (0.1%)                   |   295  |         if next_state_item && reachable.include?(next_state_item)
                                  |   296  |           # @type var t: Triple
   26    (0.2%)                   |   297  |           t = Triple.new(next_state_item, triple.l)
  230    (1.8%) /   207   (1.6%)  |   298  |           queue << [t, paths + [TransitionPath.new(triple.state_item, t.state_item)]]
                                  |   299  |         end
                                  |   300  |
                                  |   301  |         # production step
 6638   (50.5%) /    11   (0.1%)  |   302  |         @productions[triple.state_item]&.each do |item|
  792    (6.0%) /     7   (0.1%)  |   303  |           next unless reachable.include?(StateItem.new(triple.state, item))
                                  |   304  |
   55    (0.4%) /    10   (0.1%)  |   305  |           l = follow_l(triple.item, triple.l)
                                  |   306  |           # @type var t: Triple
 1090    (8.3%) /    25   (0.2%)  |   307  |           t = Triple.new(StateItem.new(triple.state, item), l)
 4665   (35.5%) /  4118  (31.3%)  |   308  |           queue << [t, paths + [ProductionPath.new(triple.state_item, t.state_item)]]
    1    (0.0%) /     1   (0.0%)  |   309  |         end
                                  |   310  |       end

Pass `StateItem` to `Triple.new` so that the number of `StateItem`
instance creation decreases.

Before:

```
$ stackprof tmp/stackprof-cpu-myapp.dump --method "Lrama::Counterexamples#shortest_path"
Lrama::Counterexamples#shortest_path (yui-knk/lrama/lib/lrama/counterexamples.rb:273)
  samples:  2752 self (21.5%)  /   4854 total (37.9%)
  callers:
    4854  (  100.0%)  Lrama::Counterexamples#reduce_reduce_examples
    3345  (   68.9%)  Hash#each_key
  callees (2102 total):
    3362  (  159.9%)  Set#each
     518  (   24.6%)  Lrama::Counterexamples::Triple#state_item
     256  (   12.2%)  Class#new
     251  (   11.9%)  Set#include?
     241  (   11.5%)  #<Class:0x0000000104f1b698>.new
     219  (   10.4%)  #<Class:0x0000000104f1c598>.new
     196  (    9.3%)  Lrama::Counterexamples#reachable_state_items
     128  (    6.1%)  Struct#hash
     107  (    5.1%)  Lrama::Counterexamples#follow_l
      65  (    3.1%)  Array#shift
      40  (    1.9%)  Struct#eql?
      27  (    1.3%)  Lrama::States::Item#next_sym
      18  (    0.9%)  Array#hash
      17  (    0.8%)  Array#eql?
       2  (    0.1%)  Lrama::State#==
  code:
                                  |   273  |     def shortest_path(conflict_state, conflict_reduce_item, conflict_term)
                                  |   274  |       queue = [] #: Array[[Triple, Array[Path::path]]]
                                  |   275  |       visited = {} #: Hash[Triple, true]
                                  |   276  |       start_state = @states.states.first #: Lrama::State
                                  |   277  |       conflict_term_bit = Bitmap::from_array([conflict_term.number])
                                  |   278  |       raise "BUG: Start state should be just one kernel." if start_state.kernels.count != 1
  196    (1.5%)                   |   279  |       reachable = reachable_state_items(StateItem.new(conflict_state, conflict_reduce_item))
                                  |   280  |       start = Triple.new(start_state, start_state.kernels.first, Bitmap::from_array([@states.eof_symbol.number]))
                                  |   281  |
                                  |   282  |       queue << [start, [StartPath.new(start.state_item)]]
                                  |   283  |
  104    (0.8%) /    39   (0.3%)  |   284  |       while (triple, paths = queue.shift)
  437    (3.4%) /   296   (2.3%)  |   285  |         next if visited[triple]
  190    (1.5%) /   175   (1.4%)  |   286  |         visited[triple] = true
                                  |   287  |
                                  |   288  |         # Found
    2    (0.0%)                   |   289  |         if (triple.state == conflict_state) && (triple.item == conflict_reduce_item) && (triple.l & conflict_term_bit != 0)
                                  |   290  |           return paths
                                  |   291  |         end
                                  |   292  |
                                  |   293  |         # transition
  150    (1.2%) /    57   (0.4%)  |   294  |         next_state_item = @transitions[[triple.state_item, triple.item.next_sym]]
   26    (0.2%) /     1   (0.0%)  |   295  |         if next_state_item && reachable.include?(next_state_item)
                                  |   296  |           # @type var t: Triple
   33    (0.3%) /     2   (0.0%)  |   297  |           t = Triple.new(next_state_item.state, next_state_item.item, triple.l)
  287    (2.2%) /   218   (1.7%)  |   298  |           queue << [t, paths + [TransitionPath.new(triple.state_item, t.state_item)]]
                                  |   299  |         end
                                  |   300  |
                                  |   301  |         # production step
 3431   (26.8%) /    26   (0.2%)  |   302  |         @Productions[triple.state_item]&.each do |item|
  469    (3.7%) /    24   (0.2%)  |   303  |           next unless reachable.include?(StateItem.new(triple.state, item))
                                  |   304  |
  118    (0.9%) /    11   (0.1%)  |   305  |           l = follow_l(triple.item, triple.l)
                                  |   306  |           # @type var t: Triple
  222    (1.7%) /    12   (0.1%)  |   307  |           t = Triple.new(triple.state, item, l)
 2534   (19.8%) /  1891  (14.8%)  |   308  |           queue << [t, paths + [ProductionPath.new(triple.state_item, t.state_item)]]
                                  |   309  |         end
```

After:

```
$ stackprof tmp/stackprof-cpu-myapp.dump --method "Lrama::Counterexamples#shortest_path"
Lrama::Counterexamples#shortest_path (yui-knk/lrama/lib/lrama/counterexamples.rb:273)
  samples:  4512 self (34.3%)  /   7467 total (56.8%)
  callers:
    7467  (  100.0%)  Lrama::Counterexamples#reduce_reduce_examples
    6605  (   88.5%)  Hash#each_key
  callees (2955 total):
    6619  (  224.0%)  Set#each
    1136  (   38.4%)  Class#new
    1095  (   37.1%)  #<Class:0x00000001047f78a8>.new
     238  (    8.1%)  Lrama::Counterexamples#reachable_state_items
     216  (    7.3%)  Set#include?
     117  (    4.0%)  Kernel#hash
      43  (    1.5%)  Lrama::Counterexamples#follow_l
      35  (    1.2%)  Lrama::States::Item#next_sym
      16  (    0.5%)  Array#shift
      13  (    0.4%)  Lrama::Counterexamples::Triple#state
       8  (    0.3%)  Array#hash
       7  (    0.2%)  Array#eql?
       5  (    0.2%)  Struct#hash
       4  (    0.1%)  Lrama::Counterexamples::Triple#state_item
       3  (    0.1%)  Struct#eql?
       3  (    0.1%)  Lrama::Counterexamples::Triple#item
       2  (    0.1%)  Lrama::State#==
  code:
                                  |   273  |     def shortest_path(conflict_state, conflict_reduce_item, conflict_term)
                                  |   274  |       queue = [] #: Array[[Triple, Array[Path::path]]]
                                  |   275  |       visited = {} #: Hash[Triple, true]
                                  |   276  |       start_state = @states.states.first #: Lrama::State
                                  |   277  |       conflict_term_bit = Bitmap::from_array([conflict_term.number])
                                  |   278  |       raise "BUG: Start state should be just one kernel." if start_state.kernels.count != 1
  238    (1.8%)                   |   279  |       reachable = reachable_state_items(StateItem.new(conflict_state, conflict_reduce_item))
                                  |   280  |       start = Triple.new(StateItem.new(start_state, start_state.kernels.first), Bitmap::from_array([@states.eof_symbol.number]))
                                  |   281  |
                                  |   282  |       queue << [start, [StartPath.new(start.state_item)]]
                                  |   283  |
   21    (0.2%) /     5   (0.0%)  |   284  |       while (triple, paths = queue.shift)
  135    (1.0%) /    18   (0.1%)  |   285  |         next if visited[triple]
   77    (0.6%) /    77   (0.6%)  |   286  |         visited[triple] = true
                                  |   287  |
                                  |   288  |         # Found
    4    (0.0%) /     1   (0.0%)  |   289  |         if (triple.state == conflict_state) && (triple.item == conflict_reduce_item) && (triple.l & conflict_term_bit != 0)
                                  |   290  |           return paths
                                  |   291  |         end
                                  |   292  |
                                  |   293  |         # transition
   83    (0.6%) /    32   (0.2%)  |   294  |         next_state_item = @transitions[[triple.state_item, triple.item.next_sym]]
   17    (0.1%)                   |   295  |         if next_state_item && reachable.include?(next_state_item)
                                  |   296  |           # @type var t: Triple
   26    (0.2%)                   |   297  |           t = Triple.new(next_state_item, triple.l)
  230    (1.8%) /   207   (1.6%)  |   298  |           queue << [t, paths + [TransitionPath.new(triple.state_item, t.state_item)]]
                                  |   299  |         end
                                  |   300  |
                                  |   301  |         # production step
 6638   (50.5%) /    11   (0.1%)  |   302  |         @Productions[triple.state_item]&.each do |item|
  792    (6.0%) /     7   (0.1%)  |   303  |           next unless reachable.include?(StateItem.new(triple.state, item))
                                  |   304  |
   55    (0.4%) /    10   (0.1%)  |   305  |           l = follow_l(triple.item, triple.l)
                                  |   306  |           # @type var t: Triple
 1090    (8.3%) /    25   (0.2%)  |   307  |           t = Triple.new(StateItem.new(triple.state, item), l)
 4665   (35.5%) /  4118  (31.3%)  |   308  |           queue << [t, paths + [ProductionPath.new(triple.state_item, t.state_item)]]
    1    (0.0%) /     1   (0.0%)  |   309  |         end
                                  |   310  |       end
```
@yui-knk yui-knk merged commit 5c58402 into ruby:master Mar 12, 2025
22 checks passed
@yui-knk yui-knk deleted the optimize_triple branch March 12, 2025 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant