concurim 0.1.0__tar.gz
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.
- concurim-0.1.0/.gitignore +14 -0
- concurim-0.1.0/CHANGELOG.md +68 -0
- concurim-0.1.0/CONTRIBUTING.md +69 -0
- concurim-0.1.0/LICENSE +21 -0
- concurim-0.1.0/PKG-INFO +95 -0
- concurim-0.1.0/README.md +65 -0
- concurim-0.1.0/SECURITY.md +37 -0
- concurim-0.1.0/docs/concepts.md +37 -0
- concurim-0.1.0/docs/cost.md +16 -0
- concurim-0.1.0/docs/getting-started.md +68 -0
- concurim-0.1.0/docs/images/logo.png +0 -0
- concurim-0.1.0/docs/images/viewer-dark.png +0 -0
- concurim-0.1.0/docs/images/viewer-light.png +0 -0
- concurim-0.1.0/docs/index.md +23 -0
- concurim-0.1.0/docs/limitations.md +207 -0
- concurim-0.1.0/docs/reading-a-run.md +62 -0
- concurim-0.1.0/docs/recording.md +93 -0
- concurim-0.1.0/docs/teaching.md +26 -0
- concurim-0.1.0/docs/trace-format.md +140 -0
- concurim-0.1.0/frontend/index.html +14 -0
- concurim-0.1.0/frontend/package-lock.json +1952 -0
- concurim-0.1.0/frontend/package.json +29 -0
- concurim-0.1.0/frontend/playwright.config.ts +21 -0
- concurim-0.1.0/frontend/src/App.tsx +121 -0
- concurim-0.1.0/frontend/src/Viewer.tsx +263 -0
- concurim-0.1.0/frontend/src/animations/palette.ts +32 -0
- concurim-0.1.0/frontend/src/api/client.ts +85 -0
- concurim-0.1.0/frontend/src/api/readDrop.ts +80 -0
- concurim-0.1.0/frontend/src/api/types.ts +117 -0
- concurim-0.1.0/frontend/src/capture.test.ts +31 -0
- concurim-0.1.0/frontend/src/capture.ts +120 -0
- concurim-0.1.0/frontend/src/captureClock.ts +43 -0
- concurim-0.1.0/frontend/src/compare/Compare.tsx +112 -0
- concurim-0.1.0/frontend/src/compare/Lanes.tsx +40 -0
- concurim-0.1.0/frontend/src/components/CodeView.tsx +107 -0
- concurim-0.1.0/frontend/src/components/Controls.tsx +90 -0
- concurim-0.1.0/frontend/src/components/EventDetail.tsx +68 -0
- concurim-0.1.0/frontend/src/components/EventLog.tsx +69 -0
- concurim-0.1.0/frontend/src/components/Explanation.tsx +25 -0
- concurim-0.1.0/frontend/src/components/Inspector.tsx +122 -0
- concurim-0.1.0/frontend/src/components/Lineage.tsx +77 -0
- concurim-0.1.0/frontend/src/components/RepoLink.tsx +14 -0
- concurim-0.1.0/frontend/src/components/StuckBanner.tsx +57 -0
- concurim-0.1.0/frontend/src/components/Timeline.tsx +178 -0
- concurim-0.1.0/frontend/src/components/TraceInfo.tsx +31 -0
- concurim-0.1.0/frontend/src/components/useSource.ts +26 -0
- concurim-0.1.0/frontend/src/export/ExportDialog.tsx +126 -0
- concurim-0.1.0/frontend/src/export/ExportFields.tsx +131 -0
- concurim-0.1.0/frontend/src/export/options.test.ts +50 -0
- concurim-0.1.0/frontend/src/export/options.ts +104 -0
- concurim-0.1.0/frontend/src/home/Gallery.tsx +198 -0
- concurim-0.1.0/frontend/src/home/Home.tsx +125 -0
- concurim-0.1.0/frontend/src/home/RunForm.tsx +116 -0
- concurim-0.1.0/frontend/src/home/RunPanel.tsx +131 -0
- concurim-0.1.0/frontend/src/home/RunProgress.tsx +58 -0
- concurim-0.1.0/frontend/src/main.tsx +16 -0
- concurim-0.1.0/frontend/src/models/compare.test.ts +41 -0
- concurim-0.1.0/frontend/src/models/compare.ts +100 -0
- concurim-0.1.0/frontend/src/models/fold.test.ts +42 -0
- concurim-0.1.0/frontend/src/models/fold.ts +58 -0
- concurim-0.1.0/frontend/src/models/layout.ts +222 -0
- concurim-0.1.0/frontend/src/models/layoutStore.ts +63 -0
- concurim-0.1.0/frontend/src/models/lineage.test.ts +47 -0
- concurim-0.1.0/frontend/src/models/lineage.ts +84 -0
- concurim-0.1.0/frontend/src/models/marks.test.ts +92 -0
- concurim-0.1.0/frontend/src/models/marks.ts +162 -0
- concurim-0.1.0/frontend/src/models/names.ts +8 -0
- concurim-0.1.0/frontend/src/models/replay.ts +210 -0
- concurim-0.1.0/frontend/src/models/resources.test.ts +46 -0
- concurim-0.1.0/frontend/src/models/resources.ts +95 -0
- concurim-0.1.0/frontend/src/models/selection.ts +4 -0
- concurim-0.1.0/frontend/src/models/states.test.ts +93 -0
- concurim-0.1.0/frontend/src/models/states.ts +59 -0
- concurim-0.1.0/frontend/src/models/sync.test.ts +135 -0
- concurim-0.1.0/frontend/src/playback/navigation.ts +34 -0
- concurim-0.1.0/frontend/src/playback/playback.test.ts +76 -0
- concurim-0.1.0/frontend/src/playback/stepping.test.ts +21 -0
- concurim-0.1.0/frontend/src/playback/stepping.ts +73 -0
- concurim-0.1.0/frontend/src/playback/useKeyboard.ts +51 -0
- concurim-0.1.0/frontend/src/playback/usePlayback.ts +75 -0
- concurim-0.1.0/frontend/src/styles/app.css +260 -0
- concurim-0.1.0/frontend/src/styles/capture.css +56 -0
- concurim-0.1.0/frontend/src/styles/export.css +43 -0
- concurim-0.1.0/frontend/src/styles/flow.css +102 -0
- concurim-0.1.0/frontend/src/styles/home.css +86 -0
- concurim-0.1.0/frontend/src/styles/theme.css +54 -0
- concurim-0.1.0/frontend/src/views/FlowToolbar.tsx +56 -0
- concurim-0.1.0/frontend/src/views/FlowView.tsx +261 -0
- concurim-0.1.0/frontend/src/views/GroupNode.tsx +38 -0
- concurim-0.1.0/frontend/src/views/ResourceView.tsx +141 -0
- concurim-0.1.0/frontend/src/views/SyncNode.tsx +104 -0
- concurim-0.1.0/frontend/src/views/Tokens.tsx +61 -0
- concurim-0.1.0/frontend/src/views/flowContext.ts +21 -0
- concurim-0.1.0/frontend/src/views/flowNodes.tsx +117 -0
- concurim-0.1.0/frontend/src/views/geometry.ts +57 -0
- concurim-0.1.0/frontend/tests/e2e/export.spec.ts +61 -0
- concurim-0.1.0/frontend/tests/e2e/graph.spec.ts +168 -0
- concurim-0.1.0/frontend/tests/e2e/home.spec.ts +221 -0
- concurim-0.1.0/frontend/tests/e2e/modes.spec.ts +70 -0
- concurim-0.1.0/frontend/tests/e2e/viewer.spec.ts +134 -0
- concurim-0.1.0/frontend/tests/e2e/visual.spec.ts +25 -0
- concurim-0.1.0/frontend/tests/e2e/visual.spec.ts-snapshots/dark-41-darwin.png +0 -0
- concurim-0.1.0/frontend/tests/e2e/visual.spec.ts-snapshots/light-101-darwin.png +0 -0
- concurim-0.1.0/frontend/tests/fixtures/asyncio-condition-sample.replay.json +1 -0
- concurim-0.1.0/frontend/tests/fixtures/asyncio-tasks-sample.replay.json +1 -0
- concurim-0.1.0/frontend/tests/fixtures/condition-mailbox-sample.replay.json +1 -0
- concurim-0.1.0/frontend/tests/fixtures/event-gate-sample.replay.json +1 -0
- concurim-0.1.0/frontend/tests/fixtures/future-control-sample.replay.json +1 -0
- concurim-0.1.0/frontend/tests/fixtures/lineage-pipeline-sample.replay.json +1 -0
- concurim-0.1.0/frontend/tests/fixtures/lock-contention-sample.replay.json +1 -0
- concurim-0.1.0/frontend/tests/fixtures/lock-order-sample.replay.json +1 -0
- concurim-0.1.0/frontend/tests/fixtures/pipeline.replay.json +1 -0
- concurim-0.1.0/frontend/tests/fixtures/process-pool-map-sample.replay.json +1 -0
- concurim-0.1.0/frontend/tests/fixtures/process-pool-sample.replay.json +1 -0
- concurim-0.1.0/frontend/tests/fixtures/process-share-sample.replay.json +1 -0
- concurim-0.1.0/frontend/tests/fixtures/semaphore-sample.replay.json +1 -0
- concurim-0.1.0/frontend/tests/fixtures/task-group-sample.replay.json +1 -0
- concurim-0.1.0/frontend/tests/fixtures/thread-pool-sample.replay.json +1 -0
- concurim-0.1.0/frontend/tsconfig.json +18 -0
- concurim-0.1.0/frontend/vite.config.ts +44 -0
- concurim-0.1.0/pyproject.toml +90 -0
- concurim-0.1.0/scripts/benchmark.py +133 -0
- concurim-0.1.0/scripts/build.sh +8 -0
- concurim-0.1.0/scripts/make_fixtures.py +66 -0
- concurim-0.1.0/scripts/make_samples.py +55 -0
- concurim-0.1.0/scripts/smoke_wheel.sh +103 -0
- concurim-0.1.0/src/concurim/__init__.py +72 -0
- concurim-0.1.0/src/concurim/__main__.py +7 -0
- concurim-0.1.0/src/concurim/cli.py +262 -0
- concurim-0.1.0/src/concurim/config.py +81 -0
- concurim-0.1.0/src/concurim/export/__init__.py +1 -0
- concurim-0.1.0/src/concurim/export/cdp.py +224 -0
- concurim-0.1.0/src/concurim/export/cli.py +110 -0
- concurim-0.1.0/src/concurim/export/options.py +99 -0
- concurim-0.1.0/src/concurim/export/sink.py +126 -0
- concurim-0.1.0/src/concurim/export/video.py +136 -0
- concurim-0.1.0/src/concurim/instrumentation/__init__.py +1 -0
- concurim-0.1.0/src/concurim/instrumentation/aio_events.py +158 -0
- concurim-0.1.0/src/concurim/instrumentation/aio_primitives.py +334 -0
- concurim-0.1.0/src/concurim/instrumentation/aio_taskgroup.py +87 -0
- concurim-0.1.0/src/concurim/instrumentation/aio_tasks.py +152 -0
- concurim-0.1.0/src/concurim/instrumentation/auto.py +251 -0
- concurim-0.1.0/src/concurim/instrumentation/auto_events.py +56 -0
- concurim-0.1.0/src/concurim/instrumentation/auto_mp.py +33 -0
- concurim-0.1.0/src/concurim/instrumentation/auto_support.py +46 -0
- concurim-0.1.0/src/concurim/instrumentation/barriers.py +213 -0
- concurim-0.1.0/src/concurim/instrumentation/executors.py +144 -0
- concurim-0.1.0/src/concurim/instrumentation/futures_support.py +132 -0
- concurim-0.1.0/src/concurim/instrumentation/mp_pool.py +272 -0
- concurim-0.1.0/src/concurim/instrumentation/mp_process.py +113 -0
- concurim-0.1.0/src/concurim/instrumentation/mp_support.py +268 -0
- concurim-0.1.0/src/concurim/instrumentation/mp_tasks.py +70 -0
- concurim-0.1.0/src/concurim/instrumentation/process_pool.py +164 -0
- concurim-0.1.0/src/concurim/instrumentation/queue_support.py +145 -0
- concurim-0.1.0/src/concurim/instrumentation/queues.py +263 -0
- concurim-0.1.0/src/concurim/instrumentation/sync.py +294 -0
- concurim-0.1.0/src/concurim/instrumentation/sync_events.py +179 -0
- concurim-0.1.0/src/concurim/instrumentation/threads.py +92 -0
- concurim-0.1.0/src/concurim/instrumentation/work.py +65 -0
- concurim-0.1.0/src/concurim/program_check.py +47 -0
- concurim-0.1.0/src/concurim/py.typed +0 -0
- concurim-0.1.0/src/concurim/recorder/__init__.py +1 -0
- concurim-0.1.0/src/concurim/recorder/collector.py +351 -0
- concurim-0.1.0/src/concurim/recorder/environment.py +110 -0
- concurim-0.1.0/src/concurim/recorder/events.py +246 -0
- concurim-0.1.0/src/concurim/recorder/flush.py +143 -0
- concurim-0.1.0/src/concurim/recorder/identities.py +27 -0
- concurim-0.1.0/src/concurim/recorder/lifecycle.py +211 -0
- concurim-0.1.0/src/concurim/recorder/sampler.py +192 -0
- concurim-0.1.0/src/concurim/recorder/serialization.py +159 -0
- concurim-0.1.0/src/concurim/replay/__init__.py +1 -0
- concurim-0.1.0/src/concurim/replay/code_view.py +71 -0
- concurim-0.1.0/src/concurim/replay/engine.py +218 -0
- concurim-0.1.0/src/concurim/replay/explanations.py +141 -0
- concurim-0.1.0/src/concurim/replay/models.py +124 -0
- concurim-0.1.0/src/concurim/replay/rules_barrier.py +83 -0
- concurim-0.1.0/src/concurim/replay/rules_events.py +191 -0
- concurim-0.1.0/src/concurim/replay/rules_exec.py +178 -0
- concurim-0.1.0/src/concurim/replay/rules_queues.py +200 -0
- concurim-0.1.0/src/concurim/replay/rules_sync.py +79 -0
- concurim-0.1.0/src/concurim/replay/rules_threads.py +101 -0
- concurim-0.1.0/src/concurim/replay/spans.py +128 -0
- concurim-0.1.0/src/concurim/replay/state.py +323 -0
- concurim-0.1.0/src/concurim/replay/state_barrier.py +79 -0
- concurim-0.1.0/src/concurim/replay/state_events.py +108 -0
- concurim-0.1.0/src/concurim/replay/state_exec.py +174 -0
- concurim-0.1.0/src/concurim/replay/state_sync.py +88 -0
- concurim-0.1.0/src/concurim/replay/state_taskgroup.py +70 -0
- concurim-0.1.0/src/concurim/replay/wait_for.py +206 -0
- concurim-0.1.0/src/concurim/runner.py +90 -0
- concurim-0.1.0/src/concurim/samples/__init__.py +32 -0
- concurim-0.1.0/src/concurim/samples/asyncio-condition.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/asyncio-queue.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/asyncio-tasks.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/asyncio_condition.py +40 -0
- concurim-0.1.0/src/concurim/samples/asyncio_queue.py +42 -0
- concurim-0.1.0/src/concurim/samples/asyncio_tasks.py +25 -0
- concurim-0.1.0/src/concurim/samples/backpressure.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/backpressure.py +48 -0
- concurim-0.1.0/src/concurim/samples/barrier.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/barrier.py +31 -0
- concurim-0.1.0/src/concurim/samples/condition-mailbox.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/condition_mailbox.py +47 -0
- concurim-0.1.0/src/concurim/samples/cpu-threads.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/cpu_threads.py +33 -0
- concurim-0.1.0/src/concurim/samples/event-gate.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/event_gate.py +37 -0
- concurim-0.1.0/src/concurim/samples/future-control.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/future_control.py +42 -0
- concurim-0.1.0/src/concurim/samples/lineage-pipeline.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/lineage_pipeline.py +70 -0
- concurim-0.1.0/src/concurim/samples/lock-contention.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/lock-order.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/lock_contention.py +40 -0
- concurim-0.1.0/src/concurim/samples/lock_order.py +43 -0
- concurim-0.1.0/src/concurim/samples/manifest.json +298 -0
- concurim-0.1.0/src/concurim/samples/plain-queues.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/plain-threads.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/plain_pipeline.py +61 -0
- concurim-0.1.0/src/concurim/samples/process-pool-map.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/process-pool.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/process-share.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/process_pool.py +31 -0
- concurim-0.1.0/src/concurim/samples/process_pool_map.py +27 -0
- concurim-0.1.0/src/concurim/samples/process_share.py +33 -0
- concurim-0.1.0/src/concurim/samples/producer-consumer.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/semaphore.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/semaphore_limit.py +34 -0
- concurim-0.1.0/src/concurim/samples/shutdown.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/shutdown.py +44 -0
- concurim-0.1.0/src/concurim/samples/task-group.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/task_group.py +30 -0
- concurim-0.1.0/src/concurim/samples/thread-pool.concurim +0 -0
- concurim-0.1.0/src/concurim/samples/thread_pool.py +30 -0
- concurim-0.1.0/src/concurim/samples/threaded_pipeline.py +72 -0
- concurim-0.1.0/src/concurim/schema/__init__.py +0 -0
- concurim-0.1.0/src/concurim/schema/event.schema.json +42 -0
- concurim-0.1.0/src/concurim/viewer/__init__.py +0 -0
- concurim-0.1.0/src/concurim/viewer/api.py +256 -0
- concurim-0.1.0/src/concurim/viewer/exports.py +197 -0
- concurim-0.1.0/src/concurim/viewer/interpreters.py +86 -0
- concurim-0.1.0/src/concurim/viewer/plan.py +52 -0
- concurim-0.1.0/src/concurim/viewer/procs.py +62 -0
- concurim-0.1.0/src/concurim/viewer/runs.py +273 -0
- concurim-0.1.0/src/concurim/viewer/server.py +197 -0
- concurim-0.1.0/src/concurim/viewer/session.py +43 -0
- concurim-0.1.0/src/concurim/viewer/static/assets/Viewer-B5HA3A02.js +8 -0
- concurim-0.1.0/src/concurim/viewer/static/assets/Viewer-DLioOiRN.css +1 -0
- concurim-0.1.0/src/concurim/viewer/static/assets/index-BHRQ-DHX.css +1 -0
- concurim-0.1.0/src/concurim/viewer/static/assets/index-Ch-8w8yu.js +11 -0
- concurim-0.1.0/src/concurim/viewer/static/assets/rolldown-runtime-WkwZ5CU-.js +1 -0
- concurim-0.1.0/src/concurim/viewer/static/index.html +16 -0
- concurim-0.1.0/src/concurim/viewer/static/logo.png +0 -0
- concurim-0.1.0/src/concurim/viewer/workspaces.py +144 -0
- concurim-0.1.0/tests/concurrency/test_stress.py +142 -0
- concurim-0.1.0/tests/conftest.py +55 -0
- concurim-0.1.0/tests/integration/test_cli_and_viewer.py +219 -0
- concurim-0.1.0/tests/integration/test_export_api.py +91 -0
- concurim-0.1.0/tests/integration/test_queue_recording.py +215 -0
- concurim-0.1.0/tests/integration/test_recording_features.py +139 -0
- concurim-0.1.0/tests/integration/test_stuck_run.py +128 -0
- concurim-0.1.0/tests/integration/test_viewer_api.py +168 -0
- concurim-0.1.0/tests/integration/test_viewer_levels.py +119 -0
- concurim-0.1.0/tests/integration/test_viewer_runs.py +272 -0
- concurim-0.1.0/tests/integration/viewer_client.py +99 -0
- concurim-0.1.0/tests/unit/pool_tasks.py +51 -0
- concurim-0.1.0/tests/unit/test_asyncio_instrumentation.py +229 -0
- concurim-0.1.0/tests/unit/test_auto_instrument.py +149 -0
- concurim-0.1.0/tests/unit/test_barriers.py +149 -0
- concurim-0.1.0/tests/unit/test_code_view.py +164 -0
- concurim-0.1.0/tests/unit/test_events.py +50 -0
- concurim-0.1.0/tests/unit/test_events_conditions.py +297 -0
- concurim-0.1.0/tests/unit/test_export.py +141 -0
- concurim-0.1.0/tests/unit/test_future_events.py +141 -0
- concurim-0.1.0/tests/unit/test_multiprocessing.py +161 -0
- concurim-0.1.0/tests/unit/test_process_pool.py +128 -0
- concurim-0.1.0/tests/unit/test_program_check.py +34 -0
- concurim-0.1.0/tests/unit/test_replay_state.py +234 -0
- concurim-0.1.0/tests/unit/test_serialization.py +90 -0
- concurim-0.1.0/tests/unit/test_sources.py +47 -0
- concurim-0.1.0/tests/unit/test_sync_instrumentation.py +256 -0
- concurim-0.1.0/tests/unit/test_taskgroup.py +135 -0
- concurim-0.1.0/tests/unit/test_wait_for.py +77 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (unreleased)
|
|
4
|
+
|
|
5
|
+
First vertical slice, then the GUI-first milestone, then locks, pools and
|
|
6
|
+
asyncio.
|
|
7
|
+
|
|
8
|
+
- The home screen shows the logo beside the name.
|
|
9
|
+
- The home screen groups examples into short lists. The home screen
|
|
10
|
+
and the player link to the GitHub repository. The README leads with
|
|
11
|
+
the commands.
|
|
12
|
+
- A short guide in `docs/`: getting started, concepts, recording,
|
|
13
|
+
reading a run, and which example to open.
|
|
14
|
+
- Barriers (`threading` and `asyncio`): who has arrived, the release
|
|
15
|
+
when the party is complete, and abort or reset. The home screen includes
|
|
16
|
+
a three-worker example.
|
|
17
|
+
- A program that does not compile is refused before it starts. A run that
|
|
18
|
+
gets stuck still leaves a trace: the buffer is flushed about once a second
|
|
19
|
+
and again on SIGINT or SIGTERM, and the viewer says who is still waiting
|
|
20
|
+
on locks one another holds. `concurim record --open` opens that picture.
|
|
21
|
+
Packaging metadata is ready for PyPI; 0.1.0 has not been uploaded.
|
|
22
|
+
- Events and conditions (`threading` and `asyncio`), `asyncio.TaskGroup`,
|
|
23
|
+
`multiprocessing` `Pool` and `Process` (copied versus shared arguments),
|
|
24
|
+
and `Future.cancel()`, callbacks and `as_completed` for thread pools.
|
|
25
|
+
- Viewer: **Lineage** tab, **Resources** layout, `concurim compare` (side by
|
|
26
|
+
side, GIL on/off, facts only), and `concurim export` (mp4/webm/gif/PNG,
|
|
27
|
+
deterministic frames with smooth, reproducible motion, optional
|
|
28
|
+
`concurim[video]` for ffmpeg), plus an **Export…** dialog in the viewer,
|
|
29
|
+
with an optional logo watermark in the top-left.
|
|
30
|
+
- Observability levels `sync` (`threading.Lock/RLock/Semaphore/
|
|
31
|
+
BoundedSemaphore`, `ThreadPoolExecutor`) and `asyncio` (tasks, `Queue`,
|
|
32
|
+
`Lock`, `Semaphore`); managed `TracedLock`, `TracedRLock`,
|
|
33
|
+
`TracedSemaphore`, `TracedBoundedSemaphore`, `TracedThreadPoolExecutor`,
|
|
34
|
+
`TracedAsync*`. Replay explains who holds or waits for each lock; asyncio
|
|
35
|
+
tasks are drawn like threads; executors like queues of tasks.
|
|
36
|
+
- `ProcessPoolExecutor` (auto at `sync`, managed `TracedProcessPoolExecutor`):
|
|
37
|
+
workers appear as processes; example `process-pool`.
|
|
38
|
+
- Code view: a task that has just started shades its **whole function body**,
|
|
39
|
+
and a background sampler (`sample_interval_ms`, with source included) then
|
|
40
|
+
follows the line each thread, asyncio task and pool worker is on (shown `≈`,
|
|
41
|
+
approximate).
|
|
42
|
+
- Viewer: **fullscreen** animation with media-style controls (`z`), a **Code**
|
|
43
|
+
mode lighting each busy worker's line in its item's colour, and a layout
|
|
44
|
+
polish (orbs inside nodes, no overflowing text).
|
|
45
|
+
- Five more examples (lock contention, semaphore, thread pool, asyncio tasks,
|
|
46
|
+
asyncio queue); queue items now keep their identity at `queues`.
|
|
47
|
+
- **Group workers** and `×N` folding of repeating log events.
|
|
48
|
+
- Viewer split into two chunks (home ~316 kB, viewer ~223 kB).
|
|
49
|
+
- CI: free-threaded 3.14t, and an experimental Windows job.
|
|
50
|
+
|
|
51
|
+
- Home screen: drop a `.concurim` trace, `.py` file or project folder; bundled
|
|
52
|
+
examples; explicit, reviewable "Record execution" with cancel and exit codes.
|
|
53
|
+
- Zero-code recording levels (`--auto none|threads|queues`), reversible.
|
|
54
|
+
- React Flow canvas with draggable, remembered layout; Motion-animated item
|
|
55
|
+
tokens; Animation/Timeline views over one recording; pacing modes; jumps.
|
|
56
|
+
- Local server: per-launch token on all POSTs, Origin/Host checks, body
|
|
57
|
+
limits, private scratch workspaces.
|
|
58
|
+
- Examples moved to `src/concurim/samples` (recordings ship in the wheel).
|
|
59
|
+
|
|
60
|
+
- `TracedQueue` (`queue.Queue` subclass), `TracedThread`, `work()` spans,
|
|
61
|
+
explicit lineage, `record()` API.
|
|
62
|
+
- `.concurim` trace format with JSON Schema, bounded buffer, truncation flag,
|
|
63
|
+
optional embedded source and payload previews.
|
|
64
|
+
- Replay engine with per-event state, blocking/join/shutdown handling, and
|
|
65
|
+
rule-based explanations that separate observed from inferred.
|
|
66
|
+
- Local viewer: animated producer/queue/consumer canvas, timeline with
|
|
67
|
+
spans and occupancy, playback controls, source panel, inspector, event log.
|
|
68
|
+
- CLI: `record`, `view`, `demo`, `inspect`.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for helping! Concurim values **accuracy over spectacle**: a visualization
|
|
4
|
+
must follow recorded events, and anything inferred must be labelled.
|
|
5
|
+
|
|
6
|
+
## Setup
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
uv sync
|
|
10
|
+
uv run pytest && uv run ruff check . && uv run ruff format --check . \
|
|
11
|
+
&& uv run ty check src
|
|
12
|
+
cd frontend && npm ci && npm test
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The compiled viewer lives in `src/concurim/viewer/static` and is committed so
|
|
16
|
+
the package works without Node. After frontend changes run
|
|
17
|
+
`scripts/build.sh` and commit the result (CI fails if it is stale).
|
|
18
|
+
Regenerate frontend fixtures with `uv run python scripts/make_fixtures.py`
|
|
19
|
+
(real capture; then refresh Playwright snapshots with
|
|
20
|
+
`npx playwright test --update-snapshots`).
|
|
21
|
+
|
|
22
|
+
## Adding an instrumented primitive
|
|
23
|
+
|
|
24
|
+
1. Add event types in `recorder/events.py` and to the JSON Schema.
|
|
25
|
+
2. Wrap the primitive in `instrumentation/`. Emit state-changing events at the
|
|
26
|
+
point where the real state changes (under the primitive's own lock if the
|
|
27
|
+
primitive offers a hook); use `mark_internal(__file__)` for source
|
|
28
|
+
attribution; never take locks that could invert with the collector's.
|
|
29
|
+
3. Add a reducer handler in `replay/state.py` and a rule in `replay/rules_*.py`.
|
|
30
|
+
4. Test with real threads. Never assert one incidental interleaving; assert
|
|
31
|
+
invariants and use events/barriers to force the situation you test.
|
|
32
|
+
5. Update `docs/limitations.md`.
|
|
33
|
+
|
|
34
|
+
## Style
|
|
35
|
+
|
|
36
|
+
Google style, 80 columns (hard limit 100), a short docstring per function,
|
|
37
|
+
files under ~300 lines (split before they grow), no duplicated logic.
|
|
38
|
+
Prefer the simplest design; do not add dependencies lightly (runtime
|
|
39
|
+
dependencies are currently zero).
|
|
40
|
+
|
|
41
|
+
## Publishing
|
|
42
|
+
|
|
43
|
+
0.1.0 is not on PyPI yet. The `pyproject.toml` metadata (SPDX license,
|
|
44
|
+
readme, classifiers, project URLs, the `concurim` script) is what the
|
|
45
|
+
upload will use. From a clean tree, after `scripts/build.sh`:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
uv build
|
|
49
|
+
uvx twine check dist/*
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Upload only when cutting the release. Do not upload from a dirty tree, and
|
|
53
|
+
do not upload over an existing version: PyPI rejects a repeated version.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
uvx twine upload dist/*
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Install paths once that version is on PyPI: `uvx concurim` (home screen;
|
|
60
|
+
the server copies itself onto the interpreter you pick) and
|
|
61
|
+
`uv add --dev concurim` when `concurim record` must import the project.
|
|
62
|
+
|
|
63
|
+
## Frontend development note
|
|
64
|
+
|
|
65
|
+
`npm run dev` proxies `/api` to the server, but POST features (opening
|
|
66
|
+
examples, dropping files, running programs) fail there: they need the
|
|
67
|
+
per-launch token the real server embeds only in the HTML it serves. For those, run `npm run build` and use `uv run concurim`.
|
|
68
|
+
Playwright starts two servers (`concurim demo` on 8799, the home screen on
|
|
69
|
+
8798) via `uv run`.
|
concurim-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Concurim contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
concurim-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: concurim
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: See how Python runs together: record and replay concurrent execution.
|
|
5
|
+
Project-URL: Homepage, https://github.com/ej-sanmartin/concurim
|
|
6
|
+
Project-URL: Documentation, https://github.com/ej-sanmartin/concurim/blob/main/docs/index.md
|
|
7
|
+
Project-URL: Source, https://github.com/ej-sanmartin/concurim
|
|
8
|
+
Project-URL: Issues, https://github.com/ej-sanmartin/concurim/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/ej-sanmartin/concurim/blob/main/CHANGELOG.md
|
|
10
|
+
Author: Concurim contributors
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: asyncio,concurrency,debugging,observability,queue,threading,visualization
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Intended Audience :: Education
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: MacOS
|
|
20
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
21
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.13
|
|
27
|
+
Provides-Extra: video
|
|
28
|
+
Requires-Dist: imageio-ffmpeg>=0.5; extra == 'video'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
<p align="center">
|
|
32
|
+
<img src="docs/images/logo.png" alt="Concurim" width="200"/>
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
# Concurim
|
|
36
|
+
|
|
37
|
+
**See how Python runs together.** Concurim records what your threads and
|
|
38
|
+
asyncio tasks actually do, then replays that one run as an animation.
|
|
39
|
+
|
|
40
|
+
## Setup
|
|
41
|
+
|
|
42
|
+
From a checkout. After 0.1.0 is on PyPI, `uvx concurim` opens the same
|
|
43
|
+
home screen.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
git clone https://github.com/ej-sanmartin/concurim.git
|
|
47
|
+
cd concurim
|
|
48
|
+
uv sync
|
|
49
|
+
|
|
50
|
+
uv run concurim
|
|
51
|
+
uv run concurim demo
|
|
52
|
+
uv run concurim record --open --auto sync my_app.py
|
|
53
|
+
uv run concurim record --open --include-source -o run.concurim my_app.py arg1
|
|
54
|
+
uv run concurim view run.concurim
|
|
55
|
+
uv run concurim inspect run.concurim
|
|
56
|
+
uv run concurim compare one.concurim two.concurim
|
|
57
|
+
uv run concurim export run.concurim -o clip.mp4 --events 5:40
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`uv run concurim` opens the page. Drop a `.py` file or a folder, read the
|
|
61
|
+
plan, then click **Record execution**. Drop a `.concurim` file, or open
|
|
62
|
+
an example, and nothing runs. Options on `record` come before the script.
|
|
63
|
+
`uvx concurim record` cannot import a project's packages; install it
|
|
64
|
+
there with `uv add --dev concurim` and use `uv run`.
|
|
65
|
+
|
|
66
|
+

|
|
67
|
+
|
|
68
|
+
*A recording of [`threaded_pipeline.py`](src/concurim/samples/threaded_pipeline.py)
|
|
69
|
+
(event 41 of 120): two producers and two consumers share a queue of
|
|
70
|
+
capacity 3.*
|
|
71
|
+
|
|
72
|
+
> **Status: 0.1 (alpha).** Not on PyPI yet. Threads, queues, locks,
|
|
73
|
+
> events, barriers, pools, and asyncio are included.
|
|
74
|
+
> [What is and is not observed](docs/limitations.md).
|
|
75
|
+
|
|
76
|
+
## Guide
|
|
77
|
+
|
|
78
|
+
| | |
|
|
79
|
+
| --- | --- |
|
|
80
|
+
| [Getting started](docs/getting-started.md) | The page, the commands, a stuck run |
|
|
81
|
+
| [Concepts](docs/concepts.md) | One schedule, observed versus inferred, what you can trust |
|
|
82
|
+
| [Recording](docs/recording.md) | Home screen, `--auto`, `record()`, `Traced*` |
|
|
83
|
+
| [Reading a run](docs/reading-a-run.md) | Animation, Code, Timeline, compare, export |
|
|
84
|
+
| [Teaching](docs/teaching.md) | Which example to open |
|
|
85
|
+
| [Cost](docs/cost.md) | Overhead of recording |
|
|
86
|
+
| [Limitations](docs/limitations.md) | Caveats |
|
|
87
|
+
| [Trace format](docs/trace-format.md) | The `.concurim` file |
|
|
88
|
+
| [Security](SECURITY.md) | Local only. Review a trace before sharing it |
|
|
89
|
+
| [Contributing](CONTRIBUTING.md) | Tests, style, publishing |
|
|
90
|
+
| [Changelog](CHANGELOG.md) | What 0.1.0 contains |
|
|
91
|
+
|
|
92
|
+
The viewer binds `127.0.0.1` and has no telemetry. Source and payload
|
|
93
|
+
previews are off unless you ask for them.
|
|
94
|
+
|
|
95
|
+
MIT licensed.
|
concurim-0.1.0/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/images/logo.png" alt="Concurim" width="200"/>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# Concurim
|
|
6
|
+
|
|
7
|
+
**See how Python runs together.** Concurim records what your threads and
|
|
8
|
+
asyncio tasks actually do, then replays that one run as an animation.
|
|
9
|
+
|
|
10
|
+
## Setup
|
|
11
|
+
|
|
12
|
+
From a checkout. After 0.1.0 is on PyPI, `uvx concurim` opens the same
|
|
13
|
+
home screen.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
git clone https://github.com/ej-sanmartin/concurim.git
|
|
17
|
+
cd concurim
|
|
18
|
+
uv sync
|
|
19
|
+
|
|
20
|
+
uv run concurim
|
|
21
|
+
uv run concurim demo
|
|
22
|
+
uv run concurim record --open --auto sync my_app.py
|
|
23
|
+
uv run concurim record --open --include-source -o run.concurim my_app.py arg1
|
|
24
|
+
uv run concurim view run.concurim
|
|
25
|
+
uv run concurim inspect run.concurim
|
|
26
|
+
uv run concurim compare one.concurim two.concurim
|
|
27
|
+
uv run concurim export run.concurim -o clip.mp4 --events 5:40
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`uv run concurim` opens the page. Drop a `.py` file or a folder, read the
|
|
31
|
+
plan, then click **Record execution**. Drop a `.concurim` file, or open
|
|
32
|
+
an example, and nothing runs. Options on `record` come before the script.
|
|
33
|
+
`uvx concurim record` cannot import a project's packages; install it
|
|
34
|
+
there with `uv add --dev concurim` and use `uv run`.
|
|
35
|
+
|
|
36
|
+

|
|
37
|
+
|
|
38
|
+
*A recording of [`threaded_pipeline.py`](src/concurim/samples/threaded_pipeline.py)
|
|
39
|
+
(event 41 of 120): two producers and two consumers share a queue of
|
|
40
|
+
capacity 3.*
|
|
41
|
+
|
|
42
|
+
> **Status: 0.1 (alpha).** Not on PyPI yet. Threads, queues, locks,
|
|
43
|
+
> events, barriers, pools, and asyncio are included.
|
|
44
|
+
> [What is and is not observed](docs/limitations.md).
|
|
45
|
+
|
|
46
|
+
## Guide
|
|
47
|
+
|
|
48
|
+
| | |
|
|
49
|
+
| --- | --- |
|
|
50
|
+
| [Getting started](docs/getting-started.md) | The page, the commands, a stuck run |
|
|
51
|
+
| [Concepts](docs/concepts.md) | One schedule, observed versus inferred, what you can trust |
|
|
52
|
+
| [Recording](docs/recording.md) | Home screen, `--auto`, `record()`, `Traced*` |
|
|
53
|
+
| [Reading a run](docs/reading-a-run.md) | Animation, Code, Timeline, compare, export |
|
|
54
|
+
| [Teaching](docs/teaching.md) | Which example to open |
|
|
55
|
+
| [Cost](docs/cost.md) | Overhead of recording |
|
|
56
|
+
| [Limitations](docs/limitations.md) | Caveats |
|
|
57
|
+
| [Trace format](docs/trace-format.md) | The `.concurim` file |
|
|
58
|
+
| [Security](SECURITY.md) | Local only. Review a trace before sharing it |
|
|
59
|
+
| [Contributing](CONTRIBUTING.md) | Tests, style, publishing |
|
|
60
|
+
| [Changelog](CHANGELOG.md) | What 0.1.0 contains |
|
|
61
|
+
|
|
62
|
+
The viewer binds `127.0.0.1` and has no telemetry. Source and payload
|
|
63
|
+
previews are off unless you ask for them.
|
|
64
|
+
|
|
65
|
+
MIT licensed.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
## Model
|
|
4
|
+
|
|
5
|
+
- The viewer is local-only: it binds `127.0.0.1`, rejects other `Host`
|
|
6
|
+
headers, sends a strict CSP, serves static files
|
|
7
|
+
with path containment, and serves source text only from the loaded trace.
|
|
8
|
+
- The viewer has a small write surface: opening a trace, uploading a program to
|
|
9
|
+
a private scratch directory, and starting/cancelling a run. Every `POST`
|
|
10
|
+
needs a per-launch token (embedded only in the served page), a same-origin
|
|
11
|
+
`Origin`, and is size-limited. Scratch files use sanitized paths and caps.
|
|
12
|
+
- **Recording runs your Python code with your user's permissions. There is no
|
|
13
|
+
sandbox.** A run starts only after the plan (command, working directory,
|
|
14
|
+
arguments, interpreter) is shown and "Record execution" is clicked. Dropping
|
|
15
|
+
a `.concurim` trace never executes anything.
|
|
16
|
+
- Traces are data: they are parsed with `json` and validated; size limits
|
|
17
|
+
apply; nothing is unpickled or executed. Strings are rendered as text.
|
|
18
|
+
- No telemetry, uploads, accounts, or network use.
|
|
19
|
+
- Auto-instrumentation (`--auto sync|asyncio`) temporarily replaces
|
|
20
|
+
standard-library factories in the recorded process only, and restores them
|
|
21
|
+
on exit. It never touches the viewer or other processes.
|
|
22
|
+
- Recording can expose information. Source embedding and payload previews are
|
|
23
|
+
opt-in; previews cover only built-in primitives, are redacted by configured
|
|
24
|
+
patterns *before* truncation, and never call `repr()` on user objects.
|
|
25
|
+
|
|
26
|
+
## Reporting
|
|
27
|
+
|
|
28
|
+
Please report vulnerabilities privately through GitHub Security Advisories on
|
|
29
|
+
the repository (or by email to the maintainers once published) instead of a
|
|
30
|
+
public issue. Include a trace or steps to reproduce. We aim to acknowledge
|
|
31
|
+
within a few days.
|
|
32
|
+
|
|
33
|
+
## Sharing traces
|
|
34
|
+
|
|
35
|
+
A `.concurim` file may contain file paths, thread names, queue names and, if
|
|
36
|
+
enabled, source code or data previews. Review with `concurim inspect` and the
|
|
37
|
+
viewer's **Trace** tab before sharing.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Concepts
|
|
2
|
+
|
|
3
|
+
Concurim records one schedule: the one this process actually ran. It
|
|
4
|
+
does not search for other interleavings, and it does not show who held
|
|
5
|
+
the GIL.
|
|
6
|
+
|
|
7
|
+
**Observed** facts come from an event. A solid border, a queue's
|
|
8
|
+
contents, and "blocked on this lock" are observed. **Inferred** facts
|
|
9
|
+
are a guess the viewer labels as such. A dashed border means the actor
|
|
10
|
+
is treated as running because nothing has said it is blocked. The
|
|
11
|
+
explanation card says when a sentence is inferred.
|
|
12
|
+
|
|
13
|
+
Recording changes timing. The picture is faithful to the instrumented
|
|
14
|
+
run, which is a bit slower than the same program with Concurim absent.
|
|
15
|
+
|
|
16
|
+
A file that does not compile is not a run. A program that starts and
|
|
17
|
+
then raises is a run, and the exception is in the trace. A program that
|
|
18
|
+
gets stuck is a run that ends at the last observed event. If threads are
|
|
19
|
+
waiting on locks one another holds, the viewer says so. That cycle is
|
|
20
|
+
read off this run. Queues and events do not name who has to move next,
|
|
21
|
+
so they are not drawn as a cycle.
|
|
22
|
+
|
|
23
|
+
Anything the chosen observability level cannot see is listed as not
|
|
24
|
+
observed. It is not filled in. The full list is in
|
|
25
|
+
[limitations](limitations.md).
|
|
26
|
+
|
|
27
|
+
## What you can trust
|
|
28
|
+
|
|
29
|
+
- Queue contents change only on recorded events, in true mutation order.
|
|
30
|
+
- Queued and unfinished are different numbers. A dequeued item leaves
|
|
31
|
+
the queue and stays unfinished until `task_done()`.
|
|
32
|
+
- `task_done()` does not say which item finished. Concurim attributes it
|
|
33
|
+
only when you pass `object_id=`. Otherwise the pairing is labeled
|
|
34
|
+
inferred.
|
|
35
|
+
- A truncated recording, an object that was not instrumented, and
|
|
36
|
+
anything unobservable (CPU scheduling, the GIL) is stated in the trace
|
|
37
|
+
and in the UI.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Cost
|
|
2
|
+
|
|
3
|
+
Measured on an Apple-silicon laptop, CPython 3.13
|
|
4
|
+
(`scripts/benchmark.py`):
|
|
5
|
+
|
|
6
|
+
| | |
|
|
7
|
+
| --- | --- |
|
|
8
|
+
| `TracedQueue` while not recording | ~2× a bare `queue.Queue` call (≈0.5 µs more) |
|
|
9
|
+
| Recording, detailed or light | ≈10 µs per put+get pair (≈20× a bare, work-free loop) |
|
|
10
|
+
| Memory while recording | ≈550 B/event (in-memory buffer) |
|
|
11
|
+
| Trace size | ≈19 B/event on disk (zip) |
|
|
12
|
+
| Load + replay | ≈1.5 s for 80k events |
|
|
13
|
+
|
|
14
|
+
The overhead matters when threads do no real work between instrumented
|
|
15
|
+
calls. With real work in between, it is usually small. Re-measure on
|
|
16
|
+
the machine you care about.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Getting started
|
|
2
|
+
|
|
3
|
+
Open the home screen and drop a program, or record from the terminal.
|
|
4
|
+
Either way you get one picture of the run that actually happened.
|
|
5
|
+
|
|
6
|
+
Commands below use `uv run concurim` from a checkout of this repo.
|
|
7
|
+
After 0.1.0 is on PyPI, `uvx concurim` is the same home screen, and
|
|
8
|
+
`uv add --dev concurim` is how `concurim record` can import a project's
|
|
9
|
+
own packages.
|
|
10
|
+
|
|
11
|
+
## Open the page
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
git clone https://github.com/ej-sanmartin/concurim.git
|
|
15
|
+
cd concurim
|
|
16
|
+
uv sync
|
|
17
|
+
uv run concurim
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The browser opens on this computer. From there:
|
|
21
|
+
|
|
22
|
+
- Drop a `.concurim` file, or open an example. Nothing runs.
|
|
23
|
+
- Drop a `.py` file or a project folder. Pick the entry point,
|
|
24
|
+
interpreter, arguments, and observability level, read the plan, then
|
|
25
|
+
click **Record execution**. The program does not run until that click.
|
|
26
|
+
When it finishes, the picture opens.
|
|
27
|
+
- **Watch so far**, while a run is still going, opens the latest saved
|
|
28
|
+
moment. That picture stays where you opened it.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
uv run concurim --port 8794 --no-browser # page only, you open the URL
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Record from the terminal
|
|
35
|
+
|
|
36
|
+
Options come before the script. Everything after the script path is
|
|
37
|
+
passed to your program.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
uv run concurim record --open my_app.py
|
|
41
|
+
uv run concurim record --open --auto sync my_app.py
|
|
42
|
+
uv run concurim record --open --include-source -o run.concurim my_app.py arg1
|
|
43
|
+
uv run concurim view run.concurim
|
|
44
|
+
uv run concurim inspect run.concurim
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`--auto` defaults to `threads`. Use `queues`, `sync`, or `asyncio` when
|
|
48
|
+
the program uses those primitives and does not import Concurim itself.
|
|
49
|
+
`--include-source` is what the Code view needs. A file that does not
|
|
50
|
+
compile is refused, and no trace is written.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv run concurim demo
|
|
54
|
+
uv run concurim compare one.concurim two.concurim
|
|
55
|
+
uv run concurim export run.concurim -o clip.mp4 --events 5:40
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`demo` records the bundled pipeline and opens it. `export` needs a
|
|
59
|
+
Chrome-family browser and ffmpeg (`uv run --with imageio-ffmpeg`, or
|
|
60
|
+
`concurim[video]` once the package is published). It only reads the
|
|
61
|
+
trace.
|
|
62
|
+
|
|
63
|
+
Ctrl-C during `record` still leaves a trace. Playback ends at the last
|
|
64
|
+
observed event. See [limitations](limitations.md) for what a stuck run
|
|
65
|
+
can and cannot show.
|
|
66
|
+
|
|
67
|
+
Next: [concepts](concepts.md), [recording](recording.md),
|
|
68
|
+
[reading a run](reading-a-run.md).
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Concurim documentation
|
|
2
|
+
|
|
3
|
+
The [README](../README.md) is the tour. These pages are the short guide.
|
|
4
|
+
|
|
5
|
+
## Read these
|
|
6
|
+
|
|
7
|
+
| | |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| [Getting started](getting-started.md) | Open the page, or record from the terminal |
|
|
10
|
+
| [Concepts](concepts.md) | One schedule, observed versus inferred |
|
|
11
|
+
| [Recording](recording.md) | Home screen, CLI, `record()`, `Traced*` |
|
|
12
|
+
| [Reading a run](reading-a-run.md) | Animation, Code, Timeline, compare, export |
|
|
13
|
+
| [Teaching](teaching.md) | Which bundled example shows which idea |
|
|
14
|
+
| [Cost](cost.md) | Overhead of recording |
|
|
15
|
+
| [Limitations](limitations.md) | What is observed, stuck programs, what is refused |
|
|
16
|
+
| [Trace format](trace-format.md) | The `.concurim` zip, for anyone building on the file |
|
|
17
|
+
| [Security](../SECURITY.md) | Local viewer, no telemetry, what a trace can contain |
|
|
18
|
+
| [Contributing](../CONTRIBUTING.md) | Tests, style, and how a PyPI upload will work |
|
|
19
|
+
| [Changelog](../CHANGELOG.md) | What 0.1.0 contains |
|
|
20
|
+
|
|
21
|
+
Video captions, a live picture that keeps updating, and a single HTML
|
|
22
|
+
file you can send someone are listed in [limitations](limitations.md)
|
|
23
|
+
and are not in 0.1.0.
|