{"id":18016894,"url":"https://github.com/fitzgen/fast-bernoulli","last_synced_at":"2025-03-26T18:32:33.559Z","repository":{"id":41437208,"uuid":"503565613","full_name":"fitzgen/fast-bernoulli","owner":"fitzgen","description":"Efficient sampling with uniform probability","archived":false,"fork":false,"pushed_at":"2022-06-16T20:55:51.000Z","size":18,"stargazers_count":31,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-17T11:59:41.301Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","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/fitzgen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-06-15T00:46:17.000Z","updated_at":"2025-01-11T23:24:17.000Z","dependencies_parsed_at":"2022-08-27T05:02:31.082Z","dependency_job_id":null,"html_url":"https://github.com/fitzgen/fast-bernoulli","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fitzgen%2Ffast-bernoulli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fitzgen%2Ffast-bernoulli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fitzgen%2Ffast-bernoulli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fitzgen%2Ffast-bernoulli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fitzgen","download_url":"https://codeload.github.com/fitzgen/fast-bernoulli/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245713149,"owners_count":20660353,"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":[],"created_at":"2024-10-30T04:19:37.711Z","updated_at":"2025-03-26T18:32:33.228Z","avatar_url":"https://github.com/fitzgen.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003e\u003ccode\u003efast-bernoulli\u003c/code\u003e\u003c/h1\u003e\n  \u003cp\u003e\n    \u003cstrong\u003eEfficient sampling with uniform probability\u003c/strong\u003e\n  \u003c/p\u003e\n  \u003cp\u003e\n    \u003ca href=\"https://github.com/fitzgen/fast-bernoulli/actions/workflows/rust.yml\"\u003e\u003cimg src=\"https://github.com/fitzgen/fast-bernoulli/actions/workflows/rust.yml/badge.svg\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://crates.io/crates/fast-bernoulli\"\u003e\u003cimg src=\"https://img.shields.io/crates/v/fast-bernoulli.svg\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://crates.io/crates/fast-bernoulli\"\u003e\u003cimg src=\"https://img.shields.io/crates/d/fast-bernoulli.svg\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://docs.rs/fast-bernoulli/\"\u003e\u003cimg src=\"https://docs.rs/fast-bernoulli/badge.svg\"/\u003e\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\nWhen gathering statistics about a program's behavior, we may be observing events\nthat occur very frequently (e.g., function calls or memory allocations) and we\nmay be gathering information that is somewhat expensive to produce (e.g., call\nstacks). Sampling all the events could have a significant impact on the\nprogram's performance.\n\nWhy not just sample every `N`'th event? This technique is called \"systematic\nsampling\"; it's simple and efficient, and it's fine if we imagine a patternless\nstream of events. But what if we're sampling allocations, and the program\nhappens to have a loop where each iteration does exactly `N` allocations? You\nwould end up sampling the same allocation every time through the loop; the\nentire rest of the loop becomes invisible to your measurements! More generally,\nif each iteration does `M` allocations, and `M` and `N` have any common divisor\nat all, most allocation sites will never be sampled. If they're both even, say,\nthe odd-numbered allocations disappear from your results.\n\nIdeally, we'd like each event to have some probability `P` of being sampled,\nindependent of its neighbors and of its position in the sequence. This is called\n[\"Bernoulli sampling\"][bernoulli-sampling], and it doesn't suffer from any of\nthe problems mentioned above.\n\n[bernoulli-sampling]: https://en.wikipedia.org/wiki/Bernoulli_sampling\n\nOne disadvantage of Bernoulli sampling is that you can't be sure exactly how\nmany samples you'll get: technically, it's possible that you might sample none\nof them, or all of them. But if the number of events `N` is large, these aren't\nlikely outcomes; you can generally expect somewhere around `P * N` events to be\nsampled.\n\nThe other disadvantage of Bernoulli sampling is that you have to generate a\nrandom number for every event, which can be slow.\n\n\u003e \u0026lt;significant pause\u0026gt;\n\nBUT NOT WITH THIS CRATE!\n\n`FastBernoulli` lets you do true Bernoulli sampling, while generating a fresh\nrandom number only when we do decide to sample an event, not on every\ntrial. When it decides not to sample, a call to `FastBernoulli::trial` is\nnothing but decrementing a counter and comparing it to zero. So the lower your\nsampling probability is, the less overhead `FastBernoulli` imposes.\n\nFinally, probabilities of `0` and `1` are handled efficiently. (In neither case\nneed we ever generate a random number at all.)\n\n## Example\n\n```rust\nuse fast_bernoulli::FastBernoulli;\nuse rand::Rng;\n\n// Get the thread-local random number generator.\nlet mut rng = rand::thread_rng();\n\n// Create a `FastBernoulli` instance that samples events with probability 1/20.\nlet mut bernoulli = FastBernoulli::new(0.05, \u0026mut rng);\n\n// Each time your event occurs, perform a Bernoulli trail to determine whether\n// you should sample the event or not.\nlet on_my_event = || {\n    if bernoulli.trial(\u0026mut rng) {\n        // Record the sample...\n    }\n};\n```\n\n## Inspiration\n\nThis crate uses the same technique that [Jim Blandy] used for [the\n`FastBernoulliTrial` class][firefox-class] in Firefox. This implementation is\nnot a direct transcription of that C++ to Rust, however I did copy (and lightly\nedit) some documentation and comments from the original (for example, most of\nthis README / crate-level documentation).\n\n[Jim Blandy]: https://www.red-bean.com/~jimb/\n[firefox-class]: https://searchfox.org/mozilla-central/rev/a6d25de0c706dbc072407ed5d339aaed1cab43b7/mfbt/FastBernoulliTrial.h\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffitzgen%2Ffast-bernoulli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffitzgen%2Ffast-bernoulli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffitzgen%2Ffast-bernoulli/lists"}