{"id":20761974,"url":"https://github.com/composewell/streamly-metrics","last_synced_at":"2026-04-20T08:02:17.420Z","repository":{"id":43486816,"uuid":"420516861","full_name":"composewell/streamly-metrics","owner":"composewell","description":"Telemetry: collecting and reporting metrics including performance counters","archived":false,"fork":false,"pushed_at":"2023-06-09T05:43:36.000Z","size":125,"stargazers_count":2,"open_issues_count":2,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-11T17:24:29.404Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/composewell.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-23T20:32:16.000Z","updated_at":"2023-03-05T13:22:24.000Z","dependencies_parsed_at":"2024-11-17T10:28:26.150Z","dependency_job_id":"d7b7042d-ef2f-4f68-9b25-2d96b3e3c53b","html_url":"https://github.com/composewell/streamly-metrics","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/composewell/streamly-metrics","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/composewell%2Fstreamly-metrics","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/composewell%2Fstreamly-metrics/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/composewell%2Fstreamly-metrics/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/composewell%2Fstreamly-metrics/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/composewell","download_url":"https://codeload.github.com/composewell/streamly-metrics/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/composewell%2Fstreamly-metrics/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32038455,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T00:18:06.643Z","status":"online","status_checked_at":"2026-04-20T02:00:06.527Z","response_time":94,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-17T10:28:20.527Z","updated_at":"2026-04-20T08:02:17.397Z","avatar_url":"https://github.com/composewell.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# streamly-metrics\n\nCollect and send performance metrics from production code.\n\nFor documentation, see the haddock docs of the following modules:\n\n* Streamly.Metrics.Channel\n* Streamly.Metrics.Perf\n\nSee a working example in the test directory - test/Main.hs.\n\n## How to analyze performance\n\n## Single threaded, non-concurrent programs\n\nSingle threaded non-cocnurrent programs are the simplest to analyze. Create a\nmetrics reporting channel using `newConsoleReporter`. Pass around this channel\nto the place where you want to measure the performance. Annotate the function\nthat you want to measure using benchOnWith. Like this:\n\n```haskell\n    chan \u003c- newConsoleReporter\n    benchOnWith chan \"sum\" $ sum [0..1000000]\n```\n\nYou can create a global channel variable if you do not want to change all the\ncode to pass around the reporting channel.\n\n```haskell\n{-# NOINLINE perfChan #-}\nperfChan :: Channel PerfMetrics\nperfChan = unsafePerformIO newConsoleReporter\n\nperf = benchOnWith perfChan\n```\n\nThen in any module just import `perf` and use it:\n\n```haskell\n    perf \"sum\" $ sum [0..1000000]\n```\n\nFor lower level APIs see bench and benchWith.\n\n## Issues with concurrent programs\n\nPrograms using Haskell threads require a bit more care for correct\nbenchmarking. The problem is that the performance measurement code collects\nmetrics from the OS which is not aware of the Haskell threads running on top of\nOS threads.\n\nThe benchmarking code collects perf metrics from the OS, runs the enclosed code\nand collects the metrics again and reports the difference. However, in presence\nof Haskell threads the code being measured may block and another Haskell thread\nmay get scheduled. Thus the perf measurement may include measurements over\nother threads as well which may not be what you want.\n\nThe following issues may arise:\n\n* The `ProcessCPUTime` metric reports the cpu time of the entire process\n  including all the OS threads or Haskell threads in the process. If a\n  measurement straddles over Haskell thread yield points, the timing reported\n  would include the timing of all the Haskell threads scheduled in between.\n* Similarly, the GC statistics would include global timings of the entire\n  process, rather than a particular thread.\n* The OS's `ThreadCPUTime` metric reports the CPUTime of the OS threads. However,\n  the OS threads are started by the Haskell RTS and they can run any Haskell\n  threads. Also, after we have taken the initial measurement our thread may be\n  scheduled on another thread and our final measurement may be taken on another\n  thread, thus the `ThreadCPUTime` would be completely unreliable in this case.\n\n## Measuring round-trip times\n\nWhen inside a looping handler that is called by some external code we would\nlike to measure the timing end-to-end from the point where the loop was\nstarted. However, we may not want to change the external library to do so. A\nconvenient way to do this is to use the special routine provided by this\nlibrary. This routine measures the time at a certain point in the program and\nends the measurement when the control flow reaches the same point again. This\nway we can measure the round trip timing (using `ThreadCPUTime`) of the loop\nwithout having to annotate the start of the loop. Though the timing of each\niteration is not measured accurately because we are measuring some part of the\nprevious iteration and rest from the next iteration, but this would average out\nover many requests and can still be a very useful metric for the cost of the\nloop.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcomposewell%2Fstreamly-metrics","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcomposewell%2Fstreamly-metrics","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcomposewell%2Fstreamly-metrics/lists"}