sass-prof 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9bdc582c7241e357559c9cb8fe3ca8a9d8ca5eb2
4
- data.tar.gz: 5a65fa2fba5c17ddb3f71fc08a3af4bba6ae7c97
3
+ metadata.gz: 74b54effd751314200217bc6a303bcb28bab0a9d
4
+ data.tar.gz: 8e72075c8d54289247ab974d5d287e558c7753ac
5
5
  SHA512:
6
- metadata.gz: f80bd2249c8002050c28609f79de4860e0a679ed321a857d28c78e5d1ef3b5fe556311b69e8febd6363fe3acff61d67549d0fa0569c2263fe50e0d9c0a0c4d39
7
- data.tar.gz: 3d9eb5c378eceae90768bd047fd111402b99ad91f0877d39a4753f0f8a1f62c9ec2337770ff8e99f1446e8adda73912a3c57362a40ed9fcf4a59e5d80f6c51b6
6
+ metadata.gz: a96c52f07b325fdb16fa7f968c622f6a29a409a1a076dc0f3b6416ca77c0f18cb37deb7317096935a34bb7005e5edaa7faf4e840140ae0c2d60aa67b21e2056c
7
+ data.tar.gz: ffd90ea32e5d162d6d560c3ecc697c60cb0653c522c98fc40151f4f51dbd38d4816cb09a36f5ee4594a98229251a87808552945d9b593a0381bb39c9a906c9bd
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ![Sass Prof](screenshot.jpg)
6
6
 
7
- Sass Prof is a code profiler for [Sass](https://github.com/sass/sass). For each function, Sass Prof will show the execution time for the function, which file called it and what arguments were given when the function was called.
7
+ Sass Prof is a code profiler for [Sass](https://github.com/sass/sass). For each `@function`, `@mixin`, `@include` and `$variable`, Sass Prof will show its execution time, which file called it and what arguments were given when it was called. Currently, `@extend` is not supported but it is a planned feature.
8
8
 
9
9
  ## Requirements
10
10
 
@@ -21,7 +21,7 @@ Sass Prof is a code profiler for [Sass](https://github.com/sass/sass). For each
21
21
  1. Remove the line `require "sass-prof"` from your `config.rb`
22
22
 
23
23
  ## Usage
24
- You may specify a few options within your `config.rb`, such as directing output to a log file.
24
+ You may specify a few options within your `config.rb`, such as ignoring certain actions or directing output to a log file.
25
25
 
26
26
  ```ruby
27
27
  require "sass-prof"
@@ -55,9 +55,22 @@ prof.color = true
55
55
  # Execution time floating point precision
56
56
  # Default is `15`
57
57
  prof.precision = 5
58
+
59
+ # Ignore certain action types during profile
60
+ # Default is `[]`
61
+ prof.ignore = [
62
+ :fundef,
63
+ :fun,
64
+ :mixdef,
65
+ :mix.
66
+ :var,
67
+ ]
68
+
69
+ # Alias for `ignore`
70
+ prof.ignore_actions = []
58
71
  ```
59
72
 
60
- _Please note: your compile times **will be slower** due to the overhead of **Sass Prof**. This library was created to help you find potential bottlenecks within your code. If you find any bugs or inconsistencies, please file an [issue](https://github.com/ezekg/sass-prof/issues) or [pull request](https://github.com/ezekg/sass-prof/pulls)._
73
+ _Please note: your compile times **will be slower** due to the overhead of Sass Prof, but I've tried to be as accurate as possible in the measurements. This library was created to help you find potential bottlenecks within your code, so I hope it succeeds in that regard. If you find any bugs or inconsistencies, please file an [issue](https://github.com/ezekg/sass-prof/issues) or [pull request](https://github.com/ezekg/sass-prof/pulls)._
61
74
 
62
75
  ## Contributing
63
76
 
@@ -3,17 +3,30 @@
3
3
  require "terminal-table"
4
4
 
5
5
  require "sass-prof/config"
6
+ require "sass-prof/timer"
6
7
  require "sass-prof/reporter"
7
8
  require "sass-prof/formatter"
8
9
  require "sass-prof/profiler"
10
+ require "sass-prof/fundef_profiler"
11
+ require "sass-prof/fun_profiler"
12
+ require "sass-prof/mixdef_profiler"
13
+ require "sass-prof/mix_profiler"
14
+ require "sass-prof/ext_profiler"
15
+ require "sass-prof/var_profiler"
9
16
 
10
17
  # Monkey patch Sass to utilize Profiler
11
18
  module Sass
12
19
  class Tree::Visitors::Perform
20
+
21
+ #
22
+ # Function definition
23
+ #
13
24
  alias_method :__visit_function, :visit_function
14
25
 
15
26
  def visit_function(node)
16
- prof = ::SassProf::Profiler.new(node.dup, :function, node.args.dup,
27
+ return __visit_function node if ::SassProf::Config.ignore.include? :fundef
28
+
29
+ prof = ::SassProf::FundefProfiler.new(node.dup, :fundef, node.args.dup,
17
30
  @environment)
18
31
  prof.start
19
32
 
@@ -24,10 +37,15 @@ module Sass
24
37
  value
25
38
  end
26
39
 
40
+ #
41
+ # Mixin definition
42
+ #
27
43
  alias_method :__visit_mixindef, :visit_mixindef
28
44
 
29
45
  def visit_mixindef(node)
30
- prof = ::SassProf::Profiler.new(node.dup, :mixin, node.args.dup,
46
+ return __visit_mixindef node if ::SassProf::Config.ignore.include? :mixdef
47
+
48
+ prof = ::SassProf::MixdefProfiler.new(node.dup, :mixdef, node.args.dup,
31
49
  @environment)
32
50
  prof.start
33
51
 
@@ -38,10 +56,15 @@ module Sass
38
56
  value
39
57
  end
40
58
 
59
+ #
60
+ # Mixin perform
61
+ #
41
62
  alias_method :__visit_mixin, :visit_mixin
42
63
 
43
64
  def visit_mixin(node)
44
- prof = ::SassProf::Profiler.new(node.dup, :include, node.args.dup,
65
+ return __visit_mixin node if ::SassProf::Config.ignore.include? :mix
66
+
67
+ prof = ::SassProf::MixProfiler.new(node.dup, :mix, node.args.dup,
45
68
  @environment)
46
69
  prof.start
47
70
 
@@ -53,16 +76,108 @@ module Sass
53
76
  end
54
77
  end
55
78
 
79
+ # class Selector::SimpleSequence
80
+ #
81
+ # #
82
+ # # Extend perform
83
+ # #
84
+ # alias_method :__do_extend, :do_extend
85
+ #
86
+ # def do_extend(extends, parent_directives, replace, seen)
87
+ # return __do_extend extends, parent_directives, replace,
88
+ # seen if ::SassProf::Config.ignore.include? :ext
89
+ #
90
+ # prof = ::SassProf::ExtProfiler.new(self, :ext, nil,
91
+ # self)
92
+ # prof.start
93
+ #
94
+ # value = __do_extend extends, parent_directives, replace, seen
95
+ #
96
+ # prof.stop
97
+ #
98
+ # value
99
+ # end
100
+ # end
101
+
56
102
  class Script::Tree::Funcall
103
+
104
+ #
105
+ # Function perform
106
+ #
57
107
  alias_method :__perform_sass_fn, :perform_sass_fn
58
108
 
59
109
  def perform_sass_fn(function, args, splat, environment)
60
- prof = ::SassProf::Profiler.new(function.dup, :invoke, args.dup,
110
+ return __perform_sass_fn function, args, splat,
111
+ environment if ::SassProf::Config.ignore.include? :fun
112
+
113
+ prof = ::SassProf::FunProfiler.new(function.dup, :fun, args.dup,
61
114
  environment.dup)
62
115
  prof.start
63
116
 
64
- value = __perform_sass_fn(
65
- function, args, splat, environment)
117
+ value = __perform_sass_fn function, args, splat, environment
118
+
119
+ prof.stop
120
+
121
+ value
122
+ end
123
+ end
124
+
125
+ class Environment
126
+
127
+ #
128
+ # Variable declare
129
+ #
130
+ alias_method :__set_var, :set_var
131
+
132
+ def set_var(name, value)
133
+ return __set_var name,
134
+ value if ::SassProf::Config.ignore.include? :var
135
+
136
+ prof = ::SassProf::VarProfiler.new(name.dup, :var, value.dup,
137
+ self)
138
+ prof.start
139
+
140
+ value = __set_var name, value
141
+
142
+ prof.stop
143
+
144
+ value
145
+ end
146
+
147
+ #
148
+ # Global variable declare
149
+ #
150
+ alias_method :__set_global_var, :set_global_var
151
+
152
+ def set_global_var(name, value)
153
+ return __set_global_var name,
154
+ value if ::SassProf::Config.ignore.include? :var
155
+
156
+ prof = ::SassProf::VarProfiler.new(name.dup, :var, value.dup,
157
+ self)
158
+ prof.start
159
+
160
+ value = __set_global_var name, value
161
+
162
+ prof.stop
163
+
164
+ value
165
+ end
166
+
167
+ #
168
+ # Local variable declare
169
+ #
170
+ alias_method :__set_local_var, :set_local_var
171
+
172
+ def set_local_var(name, value)
173
+ return __set_local_var name,
174
+ value if ::SassProf::Config.ignore.include? :var
175
+
176
+ prof = ::SassProf::VarProfiler.new(name.dup, :var, value.dup,
177
+ self)
178
+ prof.start
179
+
180
+ value = __set_local_var name, value
66
181
 
67
182
  prof.stop
68
183
 
@@ -6,9 +6,13 @@ module SassProf
6
6
  attr_accessor :quiet
7
7
  attr_accessor :color
8
8
  attr_accessor :precision
9
+ attr_accessor :subtotal
10
+ attr_accessor :ignore
9
11
 
10
12
  alias_method :max_execution_time=, :t_max=
11
13
  alias_method :max_execution_time, :t_max
14
+ alias_method :ignore_actions=, :ignore=
15
+ alias_method :ignore_actions, :ignore
12
16
 
13
17
  @t_max = 100
14
18
  @max_width = false
@@ -16,6 +20,8 @@ module SassProf
16
20
  @quiet = false
17
21
  @color = true
18
22
  @precision = 15
23
+ @subtotal = true
24
+ @ignore = []
19
25
 
20
26
  extend self
21
27
  end
@@ -0,0 +1,21 @@
1
+ module SassProf
2
+ class ExtProfiler < Profiler
3
+
4
+ def initialize(subject, action, args = nil, env = nil)
5
+ super subject, action, args, env
6
+ end
7
+
8
+ def name
9
+ @env.members.join(", ").tr "\n", ""
10
+ end
11
+
12
+ def args
13
+ @subject.members.join ", "
14
+ end
15
+
16
+ def signature
17
+ "#{Formatter.colorize(name, :blue)} < "\
18
+ "#{Formatter.colorize(args, :purple)}"
19
+ end
20
+ end
21
+ end
@@ -1,7 +1,8 @@
1
1
  module SassProf
2
2
  module Formatter
3
3
 
4
- COLORS = Hash.new("37").merge({
4
+ REGEX_ASCII = /\e\[(\d+)(;\d+)*m/
5
+ COLORS = Hash.new("37").merge({
5
6
  :black => "30",
6
7
  :red => "31",
7
8
  :green => "32",
@@ -19,26 +20,59 @@ module SassProf
19
20
  end
20
21
 
21
22
  def to_table(rows)
22
- pr = Config.precision / 3 - 5 # 5 is to account for whitespace
23
- t_ms = rows.map { |c|
24
- c[1].gsub(/\e\[(\d+)(;\d+)*m/, "").to_f }.reduce :+
23
+ t_ms = Timer.t_total
25
24
 
26
25
  return if t_ms.nil?
27
26
 
28
27
  t_ss, t_ms = t_ms.divmod 1000
29
28
  t_mm, t_ss = t_ss.divmod 60
30
29
 
31
- # Add total execution time footer
30
+ # Add summary for each action type
31
+ Timer::SUMMARIES.reject { |s| s == :t_total }.each do |summary|
32
+ break unless Config.subtotal
33
+
34
+ case summary
35
+ when /^(t_)/
36
+ sum_t_ms = Timer.send summary
37
+
38
+ next if sum_t_ms.nil?
39
+
40
+ sum_t_ss, sum_t_ms = sum_t_ms.divmod 1000
41
+ sum_t_mm, sum_t_ss = sum_t_ss.divmod 60
42
+
43
+ rows << :separator
44
+ rows << [
45
+ "subtotal",
46
+ "%.0fm %.0fs %.0fms" % [sum_t_mm, sum_t_ss, sum_t_ms],
47
+ "#{summary}".gsub(/(^(t_)|(_total)$)/, ""),
48
+ ""
49
+ ]
50
+ when /^(cnt_)/
51
+ count = Timer.send summary
52
+
53
+ next if count.nil?
54
+
55
+ rows << :separator
56
+ rows << [
57
+ "count",
58
+ "#{count}",
59
+ "#{summary}".gsub(/(^(cnt_)|(_total)$)/, ""),
60
+ ""
61
+ ]
62
+ end
63
+ end
64
+
65
+ # Add footer containing total execution time
32
66
  rows << :separator
33
67
  rows << [
34
- "Total",
35
- "%.#{pr}fm %.#{pr}fs %.#{pr}fms" % [t_mm, t_ss, t_ms],
36
- "",
68
+ "total",
69
+ "%.0fm %.0fs %.0fms" % [t_mm, t_ss, t_ms],
70
+ "all",
37
71
  ""
38
72
  ]
39
73
 
40
74
  table = Terminal::Table.new({
41
- :headings => ["File", "Execution Time", "Action", "Signature"],
75
+ :headings => ["file", "execution time", "action", "signature"],
42
76
  :rows => rows
43
77
  })
44
78
 
@@ -50,7 +84,7 @@ module SassProf
50
84
  tr_row = []
51
85
 
52
86
  row.map do |col|
53
- clean_width = col.gsub(/\e\[(\d+)(;\d+)*m/, "").length
87
+ clean_width = col.gsub(REGEX_ASCII, "").length
54
88
  diff = col.length - clean_width
55
89
 
56
90
  if clean_width > max_width
@@ -0,0 +1,8 @@
1
+ module SassProf
2
+ class FunProfiler < Profiler
3
+
4
+ def initialize(subject, action, args = nil, env = nil)
5
+ super subject, action, args, env
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module SassProf
2
+ class FundefProfiler < Profiler
3
+
4
+ def initialize(subject, action, args = nil, env = nil)
5
+ super subject, action, args, env
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module SassProf
2
+ class MixProfiler < Profiler
3
+
4
+ def initialize(subject, action, args = nil, env = nil)
5
+ super subject, action, args, env
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module SassProf
2
+ class MixdefProfiler < Profiler
3
+
4
+ def initialize(subject, action, args = nil, env = nil)
5
+ super subject, action, args, env
6
+ end
7
+ end
8
+ end
@@ -1,18 +1,16 @@
1
1
  module SassProf
2
2
  class Profiler
3
- attr_accessor :function
4
- attr_accessor :action
5
- attr_accessor :args
6
- attr_accessor :env
7
-
8
- def initialize(function, action, args = nil, env = nil)
9
- @function = function
10
- @action = action
11
- @args = args
12
- @env = env
13
- @t_total = 0
14
- @t_then = 0
15
- @t_now = 0
3
+
4
+ PERFORMABLE_ACTIONS = [:fun, :mix, :ext]
5
+
6
+ def initialize(subject, action, args = nil, env = nil)
7
+ @subject = subject
8
+ @action = action
9
+ @args = args
10
+ @env = env
11
+ @t_total = 0
12
+ @t_then = 0
13
+ @t_now = 0
16
14
  end
17
15
 
18
16
  def start
@@ -24,70 +22,77 @@ module SassProf
24
22
  t_delta = (@t_now.to_f - @t_then.to_f) * 1000.0
25
23
  @t_then, @t_total = @t_now, t_delta
26
24
 
27
- create_fn_report
25
+ # Add to total execution time
26
+ Timer.add_t_total t_delta
27
+
28
+ # Add to action's execution time and count
29
+ Timer.send "add_t_#{@action}_total", t_delta
30
+ Timer.send "add_cnt_#{@action}_total", 1
31
+
32
+ create_report
28
33
  end
29
34
 
30
35
  private
31
36
 
32
- def create_fn_report
33
- fn_report = [fn_source, fn_execution_time, fn_action,
34
- fn_signature]
37
+ def create_report
38
+ report = [source, execution_time, action, signature]
35
39
 
36
- Reporter.add_row fn_report unless Config.quiet
40
+ Reporter.add_row report
37
41
 
38
42
  if @t_total > Config.t_max && is_performable_action?
39
43
  raise RuntimeError.new Formatter.colorize(
40
- "Max execution time of #{Config.t_max}ms reached for function"\
41
- " `#{fn_name}()` (took #{@t_total.round(3)}ms)", :red)
44
+ "Max execution time of #{Config.t_max}ms reached for #{@action}"\
45
+ " `#{name}()` (took #{@t_total.round(3)}ms)", :red)
42
46
  end
43
47
  end
44
48
 
45
- def fn_execution_time
49
+ def execution_time
46
50
  color = @t_total > Config.t_max ? :red : :green
47
51
  t_exec = "%.#{Config.precision}f" % @t_total
48
52
  Formatter.colorize t_exec, color
49
53
  end
50
54
 
51
- def fn_name
55
+ def name
52
56
  case
53
- when function.respond_to?(:name)
54
- function.name
57
+ when @subject.respond_to?(:name)
58
+ @subject.name
55
59
  else
56
60
  "Unknown function"
57
61
  end
58
62
  end
59
63
 
60
- def fn_args
61
- return nil if args.nil?
64
+ def args
65
+ return nil if @args.nil?
62
66
 
63
- if args.is_a? Array
64
- args.map { |a| a.inspect }.join(", ")
67
+ if @args.is_a? Array
68
+ @args.map { |a| a.inspect }.join(", ")
65
69
  else
66
- args.to_s[1...args.length-2]
70
+ @args.to_s[1...@args.to_s.length-2]
67
71
  end
68
72
  end
69
73
 
70
- def fn_source
71
- return Formatter.colorize("Unknown file", :red) unless env
74
+ def source
75
+ return Formatter.colorize("Unknown file", :red) unless @env &&
76
+ @env.respond_to?(:options)
72
77
 
73
- orig_filename = env.options.fetch :original_filename, "Unknown file"
74
- filename = env.options.fetch :filename, "Unknown file"
78
+ orig_filename = @env.options.fetch :original_filename, "Unknown file"
79
+ filename = @env.options.fetch :filename, "Unknown file"
75
80
 
76
81
  Formatter.colorize "#{File.basename(orig_filename)}:"\
77
82
  "#{File.basename(filename)}", :yellow
78
83
  end
79
84
 
80
- def fn_action
81
- Formatter.colorize action, :yellow
85
+ def action
86
+ Formatter.colorize @action, :yellow
82
87
  end
83
88
 
84
- def fn_signature
85
- "#{Formatter.colorize(fn_name, :blue)}"\
86
- "(#{Formatter.colorize(fn_args, :purple)})"
89
+ def signature
90
+ "#{Formatter.colorize(name, :blue)}"\
91
+ "(#{Formatter.colorize(args, :purple)})"
87
92
  end
88
93
 
89
94
  def is_performable_action?
90
- [:invoke, :include, :extend].include? action
95
+ PERFORMABLE_ACTIONS.include? @action
91
96
  end
92
97
  end
93
98
  end
@@ -15,13 +15,13 @@ module SassProf
15
15
 
16
16
  def print_report
17
17
  log_report if Config.output_file
18
- puts Formatter.to_table @rows
18
+ puts Formatter.to_table @rows unless Config.quiet
19
19
  end
20
20
 
21
21
  def log_report
22
22
  File.open(Config.output_file, "a+") do |f|
23
23
  f.puts Formatter.to_table @rows.map { |r|
24
- r.map { |col| col.gsub /\e\[(\d+)(;\d+)*m/, "" } }
24
+ r.map { |col| col.gsub Formatter::REGEX_ASCII, "" } }
25
25
  end
26
26
  end
27
27
 
@@ -0,0 +1,38 @@
1
+ module SassProf
2
+ module Timer
3
+
4
+ SUMMARIES = [
5
+ :t_total,
6
+ # :m_total,
7
+ :t_var_total,
8
+ :cnt_var_total,
9
+ :cnt_var_global_total,
10
+ :cnt_var_local_total,
11
+ :t_fundef_total,
12
+ :cnt_fundef_total,
13
+ :t_fun_total,
14
+ :cnt_fun_total,
15
+ :t_mixdef_total,
16
+ :cnt_mixdef_total,
17
+ :t_mix_total,
18
+ :cnt_mix_total,
19
+ # :t_ext_total,
20
+ # :cnt_ext_total,
21
+ ]
22
+
23
+ class << self
24
+ SUMMARIES.each do |summary|
25
+ instance_variable_set "@#{summary}", 0
26
+
27
+ define_method "add_#{summary}" do |value|
28
+ prev = instance_variable_get("@#{summary}") || 0
29
+ instance_variable_set("@#{summary}", prev + value)
30
+ end
31
+
32
+ define_method "#{summary}" do
33
+ instance_variable_get("@#{summary}")
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,23 @@
1
+ module SassProf
2
+ class VarProfiler < Profiler
3
+
4
+ def initialize(subject, action, args = nil, env = nil)
5
+ super subject, action, args, env
6
+ end
7
+
8
+ def name
9
+ @subject
10
+ end
11
+
12
+ def args
13
+ return nil if @args.nil?
14
+
15
+ @args.inspect
16
+ end
17
+
18
+ def signature
19
+ "#{Formatter.colorize("$#{name}", :blue)} = "\
20
+ "#{Formatter.colorize(args, :purple)}"
21
+ end
22
+ end
23
+ end
@@ -1,5 +1,5 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module SassProf
4
- VERSION = "0.4.0"
4
+ VERSION = "0.5.0"
5
5
  end
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sass-prof
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ezekg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-02 00:00:00.000000000 Z
11
+ date: 2015-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: compass
@@ -96,9 +96,16 @@ files:
96
96
  - Rakefile
97
97
  - lib/sass-prof.rb
98
98
  - lib/sass-prof/config.rb
99
+ - lib/sass-prof/ext_profiler.rb
99
100
  - lib/sass-prof/formatter.rb
101
+ - lib/sass-prof/fun_profiler.rb
102
+ - lib/sass-prof/fundef_profiler.rb
103
+ - lib/sass-prof/mix_profiler.rb
104
+ - lib/sass-prof/mixdef_profiler.rb
100
105
  - lib/sass-prof/profiler.rb
101
106
  - lib/sass-prof/reporter.rb
107
+ - lib/sass-prof/timer.rb
108
+ - lib/sass-prof/var_profiler.rb
102
109
  - lib/sass-prof/version.rb
103
110
  - sass-prof.gemspec
104
111
  - screenshot.jpg