on master help sign in
Merge pull request #701 from michaelbjames/debugger-snapshots

Debugger snapshots

commitd29ba524676c66051e66034f64b733fc00aec9d8 authorEvan Czaplicki <info@elm-lang.org> dateThu 24 Jul 2014, 14:50 (12 years ago) parent17b2d73fd86988
1 file changed+82−16
runtime/Debugger.js+82−16
runtime/Debugger.js+82−16
@@ -20,6 +20,9 @@ Elm.debuggerAttach = function(module, hotSwapState /* =undefined */) {
2020 };
2121};
2222
23+var EVENTS_PER_SAVE = 100;
24+var eventCounter = 0;
25+
2326function dispatchElmDebuggerInit() {
2427 if (parent.window) {
2528 var dispatch = function() {
@@ -38,8 +41,10 @@ function debugModule(module, runtime) {
3841 var programPaused = false;
3942 var recordedEvents = [];
4043 var asyncCallbacks = [];
44+ var snapshots = [];
4145 var watchTracker = Elm.Native.Debug.make(runtime).watchTracker;
4246 var pauseTime = 0;
47+ var eventsUntilSnapshot = EVENTS_PER_SAVE;
4348
4449 // runtime is the prototype of wrappedRuntime
4550 // so we can access all runtime properties too
@@ -66,6 +71,8 @@ function debugModule(module, runtime) {
6671 var signalGraphNodes = flattenSignalGraph(wrappedRuntime.inputs);
6772 var tracePath = tracePathInit(runtime, debuggedModule.main);
6873
74+ snapshots.push(snapshotSignalGraph(signalGraphNodes));
75+
6976 function wrapNotify(id, v) {
7077 var timestep = runtime.timer.now();
7178
@@ -75,8 +82,9 @@ function debugModule(module, runtime) {
7582 return false;
7683 }
7784 else {
78− var changed = runtime.notify(id, v, timestep);
7985 recordEvent(id, v, timestep);
86+ var changed = runtime.notify(id, v, timestep);
87+ snapshotOnCheckpoint();
8088 if (parent.window) {
8189 parent.window.postMessage("elmNotify", window.location.origin);
8290 }
@@ -103,6 +111,7 @@ function debugModule(module, runtime) {
103111 function recordEvent(id, v, timestep) {
104112 watchTracker.pushFrame();
105113 recordedEvents.push({ id:id, value:v, timestep:timestep });
114+ eventCounter += 1;
106115 }
107116
108117 function clearAsyncCallbacks() {
@@ -115,6 +124,7 @@ function debugModule(module, runtime) {
115124
116125 function clearRecordedEvents() {
117126 recordedEvents = [];
127+ eventCounter = 0;
118128 }
119129
120130 function getRecordedEventsLength() {
@@ -133,6 +143,26 @@ function debugModule(module, runtime) {
133143 recordedEvents = events.slice();
134144 }
135145
146+ function clearSnapshots() {
147+ snapshots = [snapshotSignalGraph(signalGraphNodes)];
148+ }
149+
150+ function getSnapshotAt(i) {
151+ var snapshotEvent = Math.floor(i / EVENTS_PER_SAVE);
152+ assert(snapshotEvent < snapshots.length && snapshotEvent >= 0,
153+ "Out of bounds index: " + snapshotEvent);
154+ return snapshots[snapshotEvent];
155+ }
156+
157+ function snapshotOnCheckpoint() {
158+ if (eventsUntilSnapshot === 1) {
159+ snapshots.push(snapshotSignalGraph(signalGraphNodes));
160+ eventsUntilSnapshot = EVENTS_PER_SAVE;
161+ } else {
162+ eventsUntilSnapshot -= 1;
163+ }
164+ }
165+
136166 function setPaused() {
137167 programPaused = true;
138168 clearAsyncCallbacks();
@@ -147,7 +177,12 @@ function debugModule(module, runtime) {
147177 if (position > 0) {
148178 // If we're not unpausing at the head, then we need to dump the
149179 // events that are ahead of where we're continuing.
180+ var lastSnapshotPosition = Math.floor(position / EVENTS_PER_SAVE);
181+ eventsUntilSnapshot = EVENTS_PER_SAVE - (position % EVENTS_PER_SAVE);
182+ snapshots = snapshots.slice(0, lastSnapshotPosition + 1);
150183 recordedEvents = recordedEvents.slice(0, position);
184+ tracePath.clearTracesAfter(position);
185+ eventCounter = position;
151186 executeCallbacks(asyncCallbacks, false);
152187 }
153188 tracePath.startRecording();
@@ -169,6 +204,9 @@ function debugModule(module, runtime) {
169204 getRecordedEventAt: getRecordedEventAt,
170205 copyRecordedEvents: copyRecordedEvents,
171206 loadRecordedEvents: loadRecordedEvents,
207+ clearSnapshots: clearSnapshots,
208+ getSnapshotAt: getSnapshotAt,
209+ snapshotOnCheckpoint: snapshotOnCheckpoint,
172210 getPaused: getPaused,
173211 setPaused: setPaused,
174212 setContinue: setContinue,
@@ -180,17 +218,19 @@ function debugModule(module, runtime) {
180218function debuggerInit(debugModule, runtime, hotSwapState /* =undefined */) {
181219 var currentEventIndex = 0;
182220
183− function resetProgram() {
221+ function resetProgram(position) {
222+ var closestSnapshot = debugModule.getSnapshotAt(position);
184223 debugModule.clearAsyncCallbacks();
185− restoreSnapshot(debugModule.signalGraphNodes, debugModule.initialSnapshot);
224+ restoreSnapshot(debugModule.signalGraphNodes, closestSnapshot);
186225 redrawGraphics();
187226 }
188227
189228 function restartProgram() {
190− resetProgram();
229+ resetProgram(0);
191230 debugModule.watchTracker.clear();
192231 debugModule.tracePath.clearTraces();
193232 debugModule.clearRecordedEvents();
233+ debugModule.clearSnapshots();
194234 debugModule.setContinue(0);
195235 executeCallbacks(debugModule.initialAsyncCallbacks, true);
196236 }
@@ -207,11 +247,11 @@ function debuggerInit(debugModule, runtime, hotSwapState /* =undefined */) {
207247 restartProgram();
208248 return;
209249 }
210− resetProgram();
250+ var closestSnapshotIndex =
251+ Math.floor(currentEventIndex / EVENTS_PER_SAVE) * EVENTS_PER_SAVE;
252+ resetProgram(currentEventIndex);
211253 var continueIndex = currentEventIndex;
212− currentEventIndex = 0;
213− debugModule.tracePath.clearTraces();
214− debugModule.tracePath.startRecording();
254+ currentEventIndex = closestSnapshotIndex;
215255 stepTo(continueIndex);
216256 debugModule.setContinue(currentEventIndex);
217257 }
@@ -228,8 +268,9 @@ function debuggerInit(debugModule, runtime, hotSwapState /* =undefined */) {
228268 }
229269
230270 if (index < currentEventIndex) {
231− resetProgram();
232− currentEventIndex = 0;
271+ var closestSnapshotIndex = Math.floor(index / EVENTS_PER_SAVE) * EVENTS_PER_SAVE;
272+ resetProgram(index);
273+ currentEventIndex = closestSnapshotIndex;
233274 }
234275
235276 while (currentEventIndex < index) {
@@ -277,10 +318,19 @@ function debuggerInit(debugModule, runtime, hotSwapState /* =undefined */) {
277318 var paused = top.debug.paused;
278319 debugModule.setPaused();
279320 debugModule.loadRecordedEvents(hotSwapState.recordedEvents);
321+ var index = getMaxSteps();
322+ eventCounter = 0;
323+ debugModule.tracePath.clearTraces();
280324
281325 // draw new trace path
282326 debugModule.tracePath.startRecording();
283− stepTo(getMaxSteps());
327+ while(currentEventIndex < index) {
328+ var nextEvent = debugModule.getRecordedEventAt(currentEventIndex);
329+ eventCounter += 1;
330+ runtime.notify(nextEvent.id, nextEvent.value, nextEvent.timestep);
331+ debugModule.snapshotOnCheckpoint();
332+ currentEventIndex += 1;
333+ }
284334 debugModule.tracePath.stopRecording();
285335
286336 stepTo(hotSwapState.currentEventIndex);
@@ -356,14 +406,20 @@ function tracePathInit(runtime, signalGraphMain) {
356406 for (var id in positions) {
357407 var pos = positions[id];
358408 if (tracePositions.hasOwnProperty(id)) {
359− var points = tracePositions[id];
360− if (!pos.equals(points[points.length-1])) {
361− points.push(pos);
362− }
409+ tracePositions[id].push(pos);
363410 }
364411 else {
365412 tracePositions[id] = [pos];
366413 }
414+ if (tracePositions[id].length < eventCounter) {
415+ var padCount = eventCounter - tracePositions[id].length;
416+ var lastTracePosition = tracePositions[id][tracePositions[id].length - 1];
417+ for (var i = padCount; i--;) {
418+ tracePositions[id].push(lastTracePosition)
419+ }
420+ }
421+ assert(tracePositions[id].length === eventCounter,
422+ "We don't have a 1-1 mapping of trace positions to events");
367423 }
368424 }
369425
@@ -421,10 +477,19 @@ function tracePathInit(runtime, signalGraphMain) {
421477 recordingTraces = true;
422478 }
423479
480+ function clearTracesAfter(position) {
481+ var newTraces = {};
482+ for (var id in tracePositions) {
483+ newTraces[id] = tracePositions[id].slice(0,position);
484+ }
485+ tracePositions = newTraces;
486+ }
487+
424488 return {
425489 graphicsUpdate: graphicsUpdate,
426490 canvas: tracePathCanvas,
427491 clearTraces: clearTraces,
492+ clearTracesAfter: clearTracesAfter,
428493 stopRecording: stopRecording,
429494 startRecording: startRecording
430495 }
@@ -468,7 +533,8 @@ function snapshotSignalGraph(signalGraphNodes) {
468533};
469534
470535function restoreSnapshot(signalGraphNodes, snapshot) {
471− assert(signalGraphNodes.length == snapshot.length, "saved program state has wrong length");
536+ assert(signalGraphNodes.length == snapshot.length,
537+ "saved program state has wrong length");
472538 for (var i=0; i < signalGraphNodes.length; i++) {
473539 var node = signalGraphNodes[i];
474540 var state = snapshot[i];