{"id":19502310,"url":"https://github.com/zio/zio-profiling","last_synced_at":"2025-07-05T12:35:55.500Z","repository":{"id":37021013,"uuid":"422847798","full_name":"zio/zio-profiling","owner":"zio","description":null,"archived":false,"fork":false,"pushed_at":"2025-06-29T23:02:50.000Z","size":2490,"stargazers_count":20,"open_issues_count":4,"forks_count":6,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-06-30T00:18:54.839Z","etag":null,"topics":["profiling","scala"],"latest_commit_sha":null,"homepage":"https://zio.dev/zio-profiling","language":"Scala","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/zio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-10-30T10:20:08.000Z","updated_at":"2025-06-29T23:02:54.000Z","dependencies_parsed_at":"2024-03-10T12:29:50.369Z","dependency_job_id":"015fc7c5-c413-4362-95be-4c9610c74b7f","html_url":"https://github.com/zio/zio-profiling","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/zio/zio-profiling","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zio%2Fzio-profiling","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zio%2Fzio-profiling/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zio%2Fzio-profiling/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zio%2Fzio-profiling/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zio","download_url":"https://codeload.github.com/zio/zio-profiling/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zio%2Fzio-profiling/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263742980,"owners_count":23504564,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["profiling","scala"],"created_at":"2024-11-10T22:16:02.876Z","updated_at":"2025-07-05T12:35:55.492Z","avatar_url":"https://github.com/zio.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"[//]: # (This file was autogenerated using `zio-sbt-website` plugin via `sbt generateReadme` command.)\n[//]: # (So please do not edit it manually. Instead, change \"docs/index.md\" file or sbt setting keys)\n[//]: # (e.g. \"readmeDocumentation\" and \"readmeSupport\".)\n\n# ZIO Profiling\n\nZIO Profiling is a collection of different profilers for better understanding the runtime behavior of ZIO programs.\n\n[![Concept](https://img.shields.io/badge/Project%20Stage-Concept-orange.svg)](https://github.com/zio/zio/wiki/Project-Stages) ![CI Badge](https://github.com/zio/zio-profiling/workflows/CI/badge.svg) [![Sonatype Releases](https://img.shields.io/nexus/r/https/oss.sonatype.org/dev.zio/zio-profiling_2.13.svg?label=Sonatype%20Release)](https://oss.sonatype.org/content/repositories/releases/dev/zio/zio-profiling_2.13/) [![Sonatype Snapshots](https://img.shields.io/nexus/s/https/oss.sonatype.org/dev.zio/zio-profiling_2.13.svg?label=Sonatype%20Snapshot)](https://oss.sonatype.org/content/repositories/snapshots/dev/zio/zio-profiling_2.13/) [![javadoc](https://javadoc.io/badge2/dev.zio/zio-profiling-docs_2.13/javadoc.svg)](https://javadoc.io/doc/dev.zio/zio-profiling-docs_2.13) [![ZIO Profiling](https://img.shields.io/github/stars/zio/zio-profiling?style=social)](https://github.com/zio/zio-profiling)\n\n## Introduction\n\nNormal cpu profilers cannot really be used to profile code using an effect system. Profilers operating on a thread level will only see that threads are spending time in the evaluation loop of the effect system, producing profiles that are not useful for application developers.\n\nInstead, profiling a program written using an effect system requires a profiler that is aware of the effect system and can report where the effects were constructed / which user code the effect system is spending time on. ZIO profiling aims to be that library for the ZIO effect system.\n\nThe library focuses exclusively on cpu profiling. For heap profiling please consider using other tools such as async-profiler or VisualVM.\n\n## Installation\n\nZIO Profiling requires you to add both the main library and optionally the compiler plugin to your build.sbt:\n\n```scala\nlibraryDependencies += \"dev.zio\" %% \"zio-profiling\" % \"0.3.3\"\nlibraryDependencies += compilerPlugin(\"dev.zio\" %% \"zio-profiling-tagging-plugin\" % \"0.3.3\")\n```\n\n## Profiling an application and displaying a flamegraph\n\nFor this example we are going to use the sampling profiler to measure the cpu time used by parts of a zio program.\nAll needed definitions can be imported using:\n```scala\nimport zio.profiling.sampling._\n```\n\nThe program we want to instrument simulates performing a short and then a long computation concurrently:\n```scala\nval fast = ZIO.succeed(Thread.sleep(400))\n\nval slow = ZIO.succeed(Thread.sleep(600))\n\nval program = fast \u003c\u0026\u003e slow\n```\n\nIn order to profile the program, we wrap it with the `profile` method of the sampling profiler. Once the effect has completed\nthis will yield the profiling result. We can either manipulate the result in Scala or render it in a number of standard\nformats. In this case we are going to write it out in a format supported by https://github.com/brendangregg/FlameGraph, so we\ncan visualize it as a flamegraph.\n```scala\nSamplingProfiler\n  .profile(program)\n  .flatMap(_.stackCollapseToFile(\"profile.folded\"))\n```\n\nThe resulting file can be converted to a svg using the flamegraph.pl script ([example](img/example_sampling_profile.svg)):\n```bash\nflamegraph.pl ./examples/profile.folded \u003e profile.svg\n```\n\n## Causal Profiling\n\nZIO Profiling includes experimental support for causal profiling inspired by [coz](https://github.com/plasma-umass/coz).\n\nUsage is similar to the sampling profiler, but instead of displaying the time spent running the program it will give recommendations\nwhich parts of the program to focus on during performance tuning for biggest effect. It achieves this by iteratively artificially speeding\nup parts of the program (by slowing down all parts running concurrently) and measuring the effect on overall runtime.\n\nCheck out the paper linked in the coz repository for more details about the idea.\n\nWe can bring the causal profiler into scope with the following import:\n```scala\nimport zio.profiling.causal._\n```\n\nThis time we are using a slightly more complicated example:\n```scala\nval fast = ZIO.succeed(Thread.sleep(40))\n\nval slow1 = ZIO.succeed(Thread.sleep(20))\n\nval slow2 = ZIO.succeed(Thread.sleep(60))\n\nval slow = slow1 \u003c\u0026\u003e slow2\n\nval program = (fast \u003c\u0026\u003e slow) *\u003e\n  CausalProfiler.progressPoint(\"iteration done\")\n\nCausalProfiler(iterations = 100)\n  .profile(program.forever)\n  .flatMap(_.renderToFile(\"profile.coz\"))\n```\n\nWe also need to weave the `progressPoint` effect into our program. It will be used by the causal profiler to measure progress\nof the overall program.\n\nFinally, we can run the program using the causal profiler (notice the use of `program.forever` -- the profiler will automatically interrupt the program, until then it has to keep running)\nand save the result to a file.\n\n```scala\nCausalProfiler(iterations = 100)\n  .profile(prog.forever)\n  .flatMap(_.renderToFile(\"profile.coz\"))\n```\n\nThe file can be viewed using the [Coz Visualizer](https://plasma-umass.org/coz/) (docs/[example](img/example_causal_profile.png)).\nAs you can see, the profiler correctly tells you that you can get up to a 33% speedup by optimizing the `slow2` effect,\nbut it's impossible to get a speedup any other way.\n\n## Compiler Plugin\n\nIn order to produce actionable output, a profiler not only needs to know which line of code is currently running, but also how that location was reached.\n\nMost profilers rely on the function call hierarchy to determine this information, but the call stack is not really useful for programs using functional effect systems. The reason for this is that the normal function calls are only used to build up the program as a datastructure -- not execute it.\n\n---\n\nIt's possible to restore the proper callstack while the effects are actually getting executed (this is the approach taken by the zio.Trace machinery), but that is not the approach taken by ZIO Profiling.\n\nInstead, zio-profiling tracks the current 'callstack' of your program using FiberRefs. For this approach to work every effect should be manually annotated using `zio.profiling.CostCenter.withChildCostCenter`, which will result in a hierarchy of effect tags at runtime.\n\nAs this requires modification of large parts of user programs and is bad UX, zio-profiling ships with a compiler plugin (zio-profiling-tagging-plugin) that automates this. Every `def` or `val` that returns a zio effect will be rewritten to be properly tagged. Consider this example for the rewrite that happens:\n\n```scala\nval testEffect = ZIO.unit\n\n// gets rewritten to\n\nval testEffect = CostCenter.withChildCostCenter(\"foo.Foo.testEffect(Foo.scala:12)\")(ZIO.unit)\n```\n\nTo enable the compiler plugin, add the following to the sbt module __containing the code you want to profile__.\n\n```scala\ncompilerPlugin(\"dev.zio\" %% \"zio-profiling-tagging-plugin\" % \"0.3.3\")\n\n```\n\n## Jmh Support\n\nZIO Profiling offers an integration with the Java Microbenchmark Harness (JMH). In order to profile a jmh benchmark, first ensure that the sources are properly tagged using the tagging plugin. Next, add a dependency to the jmh module to your benchmarking module:\n```scala\nlibraryDependencies += \"dev.zio\" %% \"zio-profiling-jmh\" % \"0.3.3\"\n```\n\nIn your actual benchmarks, ensure that you are running ZIO effects using the methods in `zio.profiling.jmh.BenchmarkUtils`. A possible benchmark might look like this\n```scala\npackage zio.redis.benchmarks.lists\n\nimport org.openjdk.jmh.annotations._\nimport zio.profiling.jmh.BenchmarkUtils\nimport zio.redis._\nimport zio.redis.benchmarks._\nimport zio.{Scope =\u003e _, _}\n\nimport java.util.concurrent.TimeUnit\n\n@State(Scope.Thread)\n@BenchmarkMode(Array(Mode.Throughput))\n@OutputTimeUnit(TimeUnit.SECONDS)\n@Measurement(iterations = 15)\n@Warmup(iterations = 15)\n@Fork(2)\nclass BlMoveBenchmarks extends BenchmarkRuntime {\n\n  @Param(Array(\"500\"))\n  var count: Int = _\n\n  private var items: List[String] = _\n\n  private val key = \"test-list\"\n\n  private def execute(query: ZIO[Redis, RedisError, Unit]): Unit =\n    BenchmarkUtils.unsafeRun(query.provideLayer(BenchmarkRuntime.Layer))\n\n  @Setup(Level.Trial)\n  def setup(): Unit = {\n    items = (0 to count).toList.map(_.toString)\n    execute(ZIO.serviceWithZIO[Redis](_.rPush(key, items.head, items.tail: _*).unit))\n  }\n\n  @TearDown(Level.Trial)\n  def tearDown(): Unit =\n    execute(ZIO.serviceWithZIO[Redis](_.del(key).unit))\n\n  @Benchmark\n  def zio(): Unit = execute(\n    ZIO.foreachDiscard(items)(_ =\u003e\n      ZIO.serviceWithZIO[Redis](_.blMove(key, key, Side.Left, Side.Right, 1.second).returning[String])\n    )\n  )\n}\n```\n\nOnce the benchmark is set up properly, you can specify the profiler from the jmh command line. Using sbt-jmh, it might look like this:\n```\nJmh/run -i 3 -wi 3 -f1 -t1 -prof zio.profiling.jmh.JmhZioProfiler zio.redis.benchmarks.lists.BlMoveBenchmarks.zio\n```\n\nThe profiler output will be written to a file in the directory the JVM has been invoked from.\n\n## Documentation\n\nLearn more on the [ZIO Profiling homepage](https://zio.dev/zio-profiling/)!\n\n## Contributing\n\nFor the general guidelines, see ZIO [contributor's guide](https://zio.dev/contributor-guidelines).\n\n## Code of Conduct\n\nSee the [Code of Conduct](https://zio.dev/code-of-conduct)\n\n## Support\n\nCome chat with us on [![Badge-Discord]][Link-Discord].\n\n[Badge-Discord]: https://img.shields.io/discord/629491597070827530?logo=discord \"chat on discord\"\n[Link-Discord]: https://discord.gg/2ccFBr4 \"Discord\"\n\n## License\n\n[License](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzio%2Fzio-profiling","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzio%2Fzio-profiling","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzio%2Fzio-profiling/lists"}