gdharness 1.1.57 → 1.1.59

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,9 +12,10 @@ extends Node
12
12
 
13
13
  const Read = preload("../reading.gd")
14
14
 
15
- ## The engine sends only the top so many functions a frame and clamps nothing on the game's side.
16
- ## Its own buffer's default, so no frame is cut short of what was called.
17
- const FRAME_FUNCTIONS: int = 16384
15
+ ## The most functions a frame may carry when the server does not say. The engine names a function
16
+ ## once, as it first appears, and the game's debugger queue drops those messages past its size, so
17
+ ## the server keeps this below the queue the project sets; this is that for the engine's default.
18
+ const FRAME_FUNCTIONS: int = 1536
18
19
  const DEBUGGER_CLASS: String = "ScriptEditorDebugger"
19
20
 
20
21
 
@@ -44,6 +45,10 @@ var _started_msec: int = 0
44
45
  var _last_frame_msec: int = -1
45
46
  var _frames: int = 0
46
47
  var _complete: bool = false
48
+ var _frame_functions: int = FRAME_FUNCTIONS
49
+ ## Frames that carried as many functions as were asked for, and whether the totals did.
50
+ var _capped_frames: int = 0
51
+ var _total_capped: bool = false
47
52
  var _names: Dictionary[int, String] = {}
48
53
  ## Per signature: calls, self seconds, total seconds.
49
54
  var _totals: Dictionary[String, PackedFloat64Array] = {}
@@ -81,6 +86,8 @@ func profile_start(args: Dictionary) -> Dictionary:
81
86
  ),
82
87
  }
83
88
  _reset()
89
+ var asked: int = Read.as_int(args.get("frameFunctions", FRAME_FUNCTIONS))
90
+ _frame_functions = asked if asked > 0 else FRAME_FUNCTIONS
84
91
  if Read.as_bool(args.get("arm", false)):
85
92
  _armed = true
86
93
  return {"ok": true, "started": false, "armed": true, "session": -1}
@@ -104,6 +111,9 @@ func profile_read(_args: Dictionary) -> Dictionary:
104
111
  "playing": EditorInterface.is_playing_scene(),
105
112
  "frames": _frames,
106
113
  "complete": _complete,
114
+ "frameFunctions": _frame_functions,
115
+ "cappedFrames": _capped_frames,
116
+ "totalCapped": _total_capped,
107
117
  "coveredMs": _last_frame_msec - _started_msec if _last_frame_msec >= 0 else 0,
108
118
  "functions": functions,
109
119
  }
@@ -114,6 +124,8 @@ func _reset() -> void:
114
124
  _session = -1
115
125
  _frames = 0
116
126
  _complete = false
127
+ _capped_frames = 0
128
+ _total_capped = false
117
129
  _last_frame_msec = -1
118
130
  _names.clear()
119
131
  _totals.clear()
@@ -133,7 +145,7 @@ func _switch_on(session_id: int) -> void:
133
145
  _session = session_id
134
146
  _started_msec = Time.get_ticks_msec()
135
147
  var session: EditorDebuggerSession = _sessions.get_session(session_id)
136
- session.toggle_profiler("servers", true, [FRAME_FUNCTIONS, false])
148
+ session.toggle_profiler("servers", true, [_frame_functions, false])
137
149
 
138
150
 
139
151
  ## A play that was asked to be profiled is switched on as it starts. Any other play drops what is
@@ -170,37 +182,42 @@ func _on_debug_data(message: String, data: Array, session_id: int) -> void:
170
182
  if message == "servers:function_signature" and data.size() >= 2:
171
183
  _names[Read.as_int(data[1])] = str(data[0])
172
184
  elif message == "servers:profile_frame":
173
- if _add(data, _totals):
185
+ var carried: int = _add(data, _totals)
186
+ if carried >= 0:
174
187
  _frames += 1
188
+ _capped_frames += 1 if carried >= _frame_functions else 0
175
189
  _last_frame_msec = Time.get_ticks_msec()
176
190
  elif message == "servers:profile_total":
177
191
  # The engine's own count since the profiler started, so it replaces the frames' sum.
178
192
  var whole: Dictionary[String, PackedFloat64Array] = {}
179
- if _add(data, whole):
193
+ var carried: int = _add(data, whole)
194
+ if carried >= 0:
180
195
  _totals = whole
181
196
  _complete = true
197
+ _total_capped = carried >= _frame_functions
182
198
  _last_frame_msec = Time.get_ticks_msec()
183
199
 
184
200
 
185
201
  ## Adds one frame's functions into [param into], reading past the servers' section to reach them:
186
202
  ## six frame times, the server count, each server's name and field count and fields, then five
187
- ## numbers per function.
188
- func _add(data: Array, into: Dictionary[String, PackedFloat64Array]) -> bool:
203
+ ## numbers per function. Answers how many functions it carried, or -1 for a frame it cannot read.
204
+ func _add(data: Array, into: Dictionary[String, PackedFloat64Array]) -> int:
189
205
  var at: int = 6
190
206
  if data.size() <= at:
191
- return false
207
+ return -1
192
208
  var servers: int = Read.as_int(data[at])
193
209
  at += 1
194
210
  for _server: int in servers:
195
211
  if data.size() <= at + 1:
196
- return false
212
+ return -1
197
213
  at += 2 + Read.as_int(data[at + 1])
198
214
  if data.size() <= at:
199
- return false
215
+ return -1
200
216
  var values: int = Read.as_int(data[at])
201
217
  at += 1
202
218
  if values % 5 != 0 or data.size() < at + values:
203
- return false
219
+ return -1
220
+ var carried: int = 0
204
221
  for index: int in range(at, at + values, 5):
205
222
  var id: int = Read.as_int(data[index])
206
223
  var signature: String = _names[id] if _names.has(id) else "#%d" % id
@@ -211,4 +228,5 @@ func _add(data: Array, into: Dictionary[String, PackedFloat64Array]) -> bool:
211
228
  sum[1] += Read.as_float(data[index + 2])
212
229
  sum[2] += Read.as_float(data[index + 3])
213
230
  into[signature] = sum
214
- return true
231
+ carried += 1
232
+ return carried
@@ -172,6 +172,7 @@ func _report_errors() -> void:
172
172
  func _process(_delta: float) -> void:
173
173
  if not _enabled or _server == null:
174
174
  return
175
+ _queries.note_frame(Time.get_ticks_usec())
175
176
 
176
177
  if _server.is_connection_available():
177
178
  var client: StreamPeerTCP = _server.take_connection()
@@ -28,8 +28,14 @@ const READ_LIMIT: int = 500
28
28
  ## and said nothing, and a caller told to raise a number that stays put concludes the screen moved.
29
29
  const LIMIT_CEILING: int = 5000
30
30
 
31
+ ## How many frames the frame time is the mean of: two seconds at sixty frames a second.
32
+ const FRAMES_TIMED: int = 120
33
+
31
34
  var _host: Node
32
35
  var _values: Values
36
+ ## How long each of the last frames took, oldest first, in microseconds, as the game timed them.
37
+ var _frame_usec: PackedInt64Array = PackedInt64Array()
38
+ var _last_frame_usec: int = 0
33
39
 
34
40
 
35
41
  ## The host is the autoload, which is how the tree is reached: it is not in one when the
@@ -649,12 +655,60 @@ func get_property(params: Dictionary) -> Dictionary:
649
655
  }
650
656
 
651
657
 
658
+ ## Called by the autoload once a frame, whatever else it does that frame, with the time it was called.
659
+ ##
660
+ ## The engine's own monitors do not follow the frame: TIME_PROCESS and the frame rate are set once a
661
+ ## second, the first to the slowest process step of that second, so a game whose frames took 16.7ms
662
+ ## read 45ms for a second at a time, and a change to the game showed only on the next second's
663
+ ## worst frame. The time between two of these calls is the frame as it passed, physics and the wait
664
+ ## for the display included.
665
+ func note_frame(now_usec: int) -> void:
666
+ if _last_frame_usec > 0:
667
+ var _grew: bool = _frame_usec.push_back(now_usec - _last_frame_usec)
668
+ if _frame_usec.size() > FRAMES_TIMED:
669
+ _frame_usec.remove_at(0)
670
+ _last_frame_usec = now_usec
671
+
672
+
673
+ ## Whether the frame waits for the display, which sets its floor: a game with vsync on cannot
674
+ ## finish a frame sooner than the display refreshes, however little it does.
675
+ static func _vsync() -> String:
676
+ if DisplayServer.get_name() == "headless":
677
+ return "none, headless"
678
+ match DisplayServer.window_get_vsync_mode():
679
+ DisplayServer.VSYNC_DISABLED:
680
+ return "disabled"
681
+ DisplayServer.VSYNC_ADAPTIVE:
682
+ return "adaptive"
683
+ DisplayServer.VSYNC_MAILBOX:
684
+ return "mailbox"
685
+ _:
686
+ return "enabled"
687
+
688
+
652
689
  func get_metrics(params: Dictionary) -> Dictionary:
653
690
  var metrics: Array = params.get("metrics", [])
691
+ var timed: int = _frame_usec.size()
692
+ var total_usec: int = 0
693
+ var slowest_usec: int = 0
694
+ for one: int in _frame_usec:
695
+ total_usec += one
696
+ slowest_usec = maxi(slowest_usec, one)
697
+ # Null rather than zero before a frame has been timed: no frame took no time.
698
+ var frame_time: Variant = null
699
+ var frame_time_max: Variant = null
700
+ if timed > 0:
701
+ frame_time = float(total_usec) / timed / 1000000.0
702
+ frame_time_max = slowest_usec / 1000000.0
654
703
  var all: Dictionary = {
655
704
  "fps": Engine.get_frames_per_second(),
656
- "frame_time": Performance.get_monitor(Performance.TIME_PROCESS),
705
+ "frame_time": frame_time,
706
+ "frame_time_max": frame_time_max,
707
+ "frames_timed": timed,
708
+ "process_time_max": Performance.get_monitor(Performance.TIME_PROCESS),
657
709
  "physics_time": Performance.get_monitor(Performance.TIME_PHYSICS_PROCESS),
710
+ "vsync": _vsync(),
711
+ "max_fps": Engine.max_fps,
658
712
  "memory_static": Performance.get_monitor(Performance.MEMORY_STATIC),
659
713
  "memory_static_max": Performance.get_monitor(Performance.MEMORY_STATIC_MAX),
660
714
  "object_count": Performance.get_monitor(Performance.OBJECT_COUNT),