{"id":16572755,"url":"https://github.com/lemire/simdprune","last_synced_at":"2025-03-21T12:31:08.392Z","repository":{"id":66054950,"uuid":"89387699","full_name":"lemire/simdprune","owner":"lemire","description":"Pruning elements in SIMD vectors (i.e., packing left elements)","archived":false,"fork":false,"pushed_at":"2024-01-30T21:03:23.000Z","size":271,"stargazers_count":65,"open_issues_count":2,"forks_count":9,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-18T01:11:22.895Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","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/lemire.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":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-04-25T17:22:34.000Z","updated_at":"2025-03-06T19:24:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"55044714-e8f0-4ecf-81ce-3740a08fda19","html_url":"https://github.com/lemire/simdprune","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemire%2Fsimdprune","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemire%2Fsimdprune/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemire%2Fsimdprune/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemire%2Fsimdprune/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lemire","download_url":"https://codeload.github.com/lemire/simdprune/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244799287,"owners_count":20512224,"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-11T21:28:30.164Z","updated_at":"2025-03-21T12:31:07.977Z","avatar_url":"https://github.com/lemire.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# simdprune\nPruning elements in SIMD vectors\n\nSuppose that you are given an vector like 0,1,1,0,3,1,1,4 and you want to remove\nall 1s to get 0,0,3,4,... One way to do this is to compare the original vector\nwith the  vector  1,1,1,1,1,1,1,1 to get the mask 0b01100110 (where a 1 appears if and only if the corresponding elements are equal). We then want to\npass the mask 0b01100110 and the vector 0,1,1,0,3,1,1,4 to some function that\nwill produce a vector that begins with 0,0,3,4, skipping the 1s.\n\n\nThe AVX-512 instruction sets offer ``vcompress`` instructions for this purpose, but other\ninstructions sets like SSSE3 or AVX2 provide no help. \n\nThat's where this library comes in.\n\nFurther documentation: [Quickly pruning elements in SIMD vectors using the simdprune library](http://lemire.me/blog/2017/04/25/quickly-pruning-elements-in-simd-vectors-using-the-simdprune-library/)\n\n## On processors benefiting from advanced AVX-512 instructions\n\nThe AVX-512 instruction set ``vcompress`` helps but is limited to 32-bit and 64-bit words. \n\n## On ARM processors\n\nSome ARM processors will benefit from Scalable Vector Extensions. It seems that a sequence of SPLICE and INCP instructions can effectively achieve arbitrary prunning. ARM Scalable Vector Extensions also support a related instruction (``compact``) but it also seems to be limited to 32-bit and 64-bit words. \n\n## Practical examples\n\n- [Removing duplicates from lists quickly](http://lemire.me/blog/2017/04/10/removing-duplicates-from-lists-quickly/)\n- [How quickly can you remove spaces from a string?](http://lemire.me/blog/2017/01/20/how-quickly-can-you-remove-spaces-from-a-string/)\n\n## Usage\n\nTo prune every other value:\n\n```\n  // 128-bit vectors (SSSE3)\n  prune_epi8(x,0b1010101010101010);\n  prune_epi16(x,0b10101010);\n  prune_epi32(x,0b1010);\n  // 256-bit vectors (AVX2)\n  prune256_epi32(x,0b10101010);\n```\nReplacing the various masks by, say, ``0b1`` would prune just the first value.\n\n## How fast is it?\n\nThe throughput of these functions is likely quite good. The latency spans several cycles, however. Especially expensive is\n``prune_epi8`` due to its large table.\n\nThese numbers assume that one is able to hide the cache/RAM latency by prefetching the bit masks. Table lookups from RAM\ntake dozens of cycles at least.\n\n```\n  gcc -o benchmark benchmark.c  -mbmi2 -mavx2 -O3 \u0026\u0026 ./benchmark\nThis test measures the latency in CPU cycles.\nrdtsc_overhead set to 26\nrunprune_epi8(bitmasks, N, \u0026x)                              \t:  3.788 cycles per operation (best) \t4.049 cycles per operation (avg)\nrunthinprune_epi8(bitmasks, N, \u0026x)                          \t:  6.678 cycles per operation (best) \t6.719 cycles per operation (avg)\nrunskinnyprune_epi8(bitmasks, N, \u0026x)                        \t:  3.789 cycles per operation (best) \t3.799 cycles per operation (avg)\nrunprune_epi16(bitmasks, N, \u0026x)                             \t:  1.963 cycles per operation (best) \t1.986 cycles per operation (avg)\nrunprune_epi32(bitmasks, N, \u0026x)                             \t:  1.950 cycles per operation (best) \t1.957 cycles per operation (avg)\nrunprune256_epi32(bitmasks, N, \u0026xx)                         \t:  2.888 cycles per operation (best) \t2.911 cycles per operation (avg)\nrunpext_prune256_epi32(bitmasks, N, \u0026xx)                    \t:  2.875 cycles per operation (best) \t2.884 cycles per operation (avg)\n```\n\nWhy is ``runthinprune_epi8`` so much slower than ``runprune_epi8``? In part because it uses a tiny lookup table and trades reduce memory\nusage for much lower speed.\n\n## How to install\n\nJust copy the header files and include them.  Look at ``demo.c`` for an example.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flemire%2Fsimdprune","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flemire%2Fsimdprune","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flemire%2Fsimdprune/lists"}