Skip to content

Commit

Permalink
Twitter large card
Browse files Browse the repository at this point in the history
  • Loading branch information
purplesyringa committed Aug 13, 2024
1 parent 248d129 commit d4b75bf
Show file tree
Hide file tree
Showing 7 changed files with 12 additions and 5 deletions.
2 changes: 2 additions & 0 deletions blog/_template.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
<meta property="og:description" content="{{ description }}" />
<meta property="og:locale" content="{{ locale }}" />
<meta property="og:site_name" content="purplesyringa's blog" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content="https://purplesyringa.moe/blog/{{ path }}/og.png" />
</head>
<body>
<header>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<!doctypehtml><meta charset=utf-8><meta content=width=device-width,initial-scale=1 name=viewport><title>I thought I was smart enough to play with fire | purplesyringa's blog</title><link href=../../all.css rel=stylesheet><link href=../../blog.css rel=stylesheet><link href=../../vendor/Temml-Local.css rel=stylesheet><link crossorigin href=https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto:ital,wght@0,400;0,700;1,400;1,700&family=Slabo+27px&display=swap rel=stylesheet><link media="screen and (prefers-color-scheme: dark"href=../../vendor/atom-one-dark.min.css rel=stylesheet><link media="screen and (prefers-color-scheme: light"href=../../vendor/atelier-cave-light.min.css rel=stylesheet><link title="Blog posts"href=../../blog/feed.rss rel=alternate type=application/rss+xml><body><header><div class=viewport-container><div class=media><a href=https://github.com/purplesyringa><img src=../../images/github-mark-white.svg></a></div><h1><a href=/>purplesyringa</a></h1><nav><a href=../..>about</a><a class=current href=../../blog/>blog</a><a href=../../sink/>kitchen sink</a></nav></div></header><section><div class=viewport-container><h2>I thought I was smart enough to play with fire</h2><time>June 20, 2024</time><p><a href=https://codeforces.com/blog/entry/126390>blazingio</a> cuts corners by design. It keeps the constant factor small and uses long forgotten algorithms people used before processors supported SIMD and integer division. But another limitation made this task much harder.<p>Size.<p>Professional libraries start exceeding the <a href=https://codeforces.com>Codeforces</a> limit of 64 KiB really fast. Code minification barely helps, and neither does resorting to ugly code. So I cut a corner I don’t typically cut.<p>Undefined Behavior.<p>These two words make a seasoned programmer shudder. But sidestepping UB increases code size so much the library can hardly be used on CF. So I took a gamble. I meticulously scanned every instance of UB I used intentionally and made sure the compiler had absolutely no reason to miscompile it. I wrote excessive tests and run them on CI on all architecture and OS combinations I could think of. I released the library without so much as a flaw. It worked like clockwork.<p>And then, 3 months later, I updated README, and all hell broke loose.<hr><p>CI retested the code, and two compiler/OS/architecture combinations failed: MinGW on 64-bit and 32-bit Windows. Both failed on a very particular test: <code>round-trip-bitset</code> on blazingio using SSE 4.1, file I/O, built without interactive problem support.<p>It took some time to figure what the problem even was, but eventually it turned out reading into bitsets didn’t modify them. Here’s how the bitset input tight loop looked like on SSE 4.1:<pre><code class=language-cpp><span class=hljs-comment>// This is actually 0x0001020304050607</span>
<!doctypehtml><html prefix="og: http://ogp.me/ns#"lang=en_US><meta charset=utf-8><meta content=width=device-width,initial-scale=1 name=viewport><title>I thought I was smart enough to play with fire | purplesyringa's blog</title><link href=../../all.css rel=stylesheet><link href=../../blog.css rel=stylesheet><link href=../../vendor/Temml-Local.css rel=stylesheet><link crossorigin href=https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto:ital,wght@0,400;0,700;1,400;1,700&family=Slabo+27px&display=swap rel=stylesheet><link media="screen and (prefers-color-scheme: dark"href=../../vendor/atom-one-dark.min.css rel=stylesheet><link media="screen and (prefers-color-scheme: light"href=../../vendor/atelier-cave-light.min.css rel=stylesheet><link title="Blog posts"href=../../blog/feed.rss rel=alternate type=application/rss+xml><meta content="I thought I was smart enough to play with fire"property=og:title><meta content=article property=og:type><meta content=https://purplesyringa.moe/blog/i-thought-i-was-smart-enough-to-play-with-fire/og.png property=og:image><meta content=https://purplesyringa.moe/blog/i-thought-i-was-smart-enough-to-play-with-fire/ property=og:url><meta content="blazingio cuts corners by design. It keeps the constant factor small and uses long forgotten algorithms people used before processors supported SIMD and integer division. But another limitation made this task much harder.
Size.
Professional libraries start exceeding the Codeforces limit of 64 KiB really fast. Code minification barely helps, and neither does resorting to ugly code. So I cut a corner I don’t typically cut.
Undefined Behavior.
These two words make a seasoned programmer shudder. But sidestepping UB increases code size so much the library can hardly be used on CF. So I took a gamble. I meticulously scanned every instance of UB I used intentionally and made sure the compiler had absolutely no reason to miscompile it. I wrote excessive tests and run them on CI on all architecture and OS combinations I could think of. I released the library without so much as a flaw. It worked like clockwork.
And then, 3 months later, I updated README, and all hell broke loose."property=og:description><meta content=en_US property=og:locale><meta content="purplesyringa's blog"property=og:site_name><meta content=summary_large_image name=twitter:card><meta content=https://purplesyringa.moe/blog/i-thought-i-was-smart-enough-to-play-with-fire/og.png name=twitter:image><body><header><div class=viewport-container><div class=media><a href=https://github.com/purplesyringa><img src=../../images/github-mark-white.svg></a></div><h1><a href=/>purplesyringa</a></h1><nav><a href=../..>about</a><a class=current href=../../blog/>blog</a><a href=../../sink/>kitchen sink</a></nav></div></header><section><div class=viewport-container><h2>I thought I was smart enough to play with fire</h2><time>June 20, 2024</time><p><a href=https://codeforces.com/blog/entry/126390>blazingio</a> cuts corners by design. It keeps the constant factor small and uses long forgotten algorithms people used before processors supported SIMD and integer division. But another limitation made this task much harder.<p>Size.<p>Professional libraries start exceeding the <a href=https://codeforces.com>Codeforces</a> limit of 64 KiB really fast. Code minification barely helps, and neither does resorting to ugly code. So I cut a corner I don’t typically cut.<p>Undefined Behavior.<p>These two words make a seasoned programmer shudder. But sidestepping UB increases code size so much the library can hardly be used on CF. So I took a gamble. I meticulously scanned every instance of UB I used intentionally and made sure the compiler had absolutely no reason to miscompile it. I wrote excessive tests and run them on CI on all architecture and OS combinations I could think of. I released the library without so much as a flaw. It worked like clockwork.<p>And then, 3 months later, I updated README, and all hell broke loose.<hr><p>CI retested the code, and two compiler/OS/architecture combinations failed: MinGW on 64-bit and 32-bit Windows. Both failed on a very particular test: <code>round-trip-bitset</code> on blazingio using SSE 4.1, file I/O, built without interactive problem support.<p>It took some time to figure what the problem even was, but eventually it turned out reading into bitsets didn’t modify them. Here’s how the bitset input tight loop looked like on SSE 4.1:<pre><code class=language-cpp><span class=hljs-comment>// This is actually 0x0001020304050607</span>
<span class=hljs-type>uint64_t</span> a = ~<span class=hljs-number>0ULL</span> / <span class=hljs-number>65025</span>;
((<span class=hljs-type>uint16_t</span>*)&value)[i / <span class=hljs-number>16</span>] = _mm_movemask_epi8(
_mm_shuffle_epi8(
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion blog/recovering-garbled-bitcoin-addresses/index.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion blog/ru/base64-has-a-fixed-point/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
$ base64 | base64 | base64 | base64 | base64 | base64 | base64 | base64 | base64 \
| base64 | base64 | base64 | base64 | base64 | base64 | base64 | base64 | base64 | base64 \
| base64 | head -1
Vm0wd2QyUXlVWGxWV0d4V1YwZDRWMVl3WkRSV01WbDNXa1JTVjAxV2JETlhhMUpUVmpBeFYySkVU"property=og:description><meta content=ru_RU property=og:locale><meta content="purplesyringa's blog"property=og:site_name><body><header><div class=viewport-container><div class=media><a href=https://github.com/purplesyringa><img src=../../../images/github-mark-white.svg></a></div><h1><a href=/>purplesyringa</a></h1><nav><a href=../../..>about</a><a class=current href=../../../blog/>blog</a><a href=../../../sink/>kitchen sink</a></nav></div></header><section><div class=viewport-container><h2>У base64 есть неподвижная точка</h2><time>August 3, 2024</time><p><em>Пост написан по мотивам <a href=https://www.reddit.com/r/compsci/comments/18234a/the_base64_encoder_has_a_fixed_point/>давнего треда на Reddit</a>.</em><pre><code class=language-shell><span class="hljs-meta prompt_">$ </span><span class=language-bash>&LT/dev/urandom <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> \
Vm0wd2QyUXlVWGxWV0d4V1YwZDRWMVl3WkRSV01WbDNXa1JTVjAxV2JETlhhMUpUVmpBeFYySkVU"property=og:description><meta content=ru_RU property=og:locale><meta content="purplesyringa's blog"property=og:site_name><meta content=summary_large_image name=twitter:card><meta content=https://purplesyringa.moe/blog/ru/base64-has-a-fixed-point/og.png name=twitter:image><body><header><div class=viewport-container><div class=media><a href=https://github.com/purplesyringa><img src=../../../images/github-mark-white.svg></a></div><h1><a href=/>purplesyringa</a></h1><nav><a href=../../..>about</a><a class=current href=../../../blog/>blog</a><a href=../../../sink/>kitchen sink</a></nav></div></header><section><div class=viewport-container><h2>У base64 есть неподвижная точка</h2><time>August 3, 2024</time><p><em>Пост написан по мотивам <a href=https://www.reddit.com/r/compsci/comments/18234a/the_base64_encoder_has_a_fixed_point/>давнего треда на Reddit</a>.</em><pre><code class=language-shell><span class="hljs-meta prompt_">$ </span><span class=language-bash>&LT/dev/urandom <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> \
| <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>base64</span> \
| <span class=hljs-built_in>base64</span> | <span class=hljs-built_in>head</span> -1</span>
Vm0wd2QyUXlVWGxWV0d4V1YwZDRWMVl3WkRSV01WbDNXa1JTVjAxV2JETlhhMUpUVmpBeFYySkVU
Expand Down
2 changes: 1 addition & 1 deletion blog/the-sentinel-trick/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Write element by index in O ( 1 ) ,
Replace all elements with a given value in O ( 1 ) .
It is not a novel technique by any means, but it doesn’t seem on everyone’s lips, so some of you might find it interesting."property=og:description><meta content=en_US property=og:locale><meta content="purplesyringa's blog"property=og:site_name><body><header><div class=viewport-container><div class=media><a href=https://github.com/purplesyringa><img src=../../images/github-mark-white.svg></a></div><h1><a href=/>purplesyringa</a></h1><nav><a href=../..>about</a><a class=current href=../../blog/>blog</a><a href=../../sink/>kitchen sink</a></nav></div></header><section><div class=viewport-container><h2>The sentinel trick</h2><time>August 13, 2024</time><p>The sentinel trick underlies a data structure with the following requirements:<ul><li>Read element by index in <eq><math><mrow><mi>O</mi><mo form=prefix stretchy=false>(</mo><mn>1</mn><mo form=postfix stretchy=false>)</mo></mrow></math></eq>,<li>Write element by index in <eq><math><mrow><mi>O</mi><mo form=prefix stretchy=false>(</mo><mn>1</mn><mo form=postfix stretchy=false>)</mo></mrow></math></eq>,<li>Replace all elements with a given value in <eq><math><mrow><mi>O</mi><mo form=prefix stretchy=false>(</mo><mn>1</mn><mo form=postfix stretchy=false>)</mo></mrow></math></eq>.</ul><p>It is not a novel technique by any means, but it doesn’t seem on everyone’s lips, so some of you might find it interesting.<h3>Why?</h3><p>We could just use a hashmap and store a “default” value. Clearing a hashmap requires no more time than writes do, so the amortized time is <eq><math><mrow><mi>O</mi><mo form=prefix stretchy=false>(</mo><mn>1</mn><mo form=postfix stretchy=false>)</mo></mrow></math></eq> for all three operations.<p>But hashmaps are notoriously slow. If I want an array, I don’t want random access all around my too-large-to-fit-into-cache data.<p>The sentinel trick provides <code>clear</code> for arrays.<h3>How?</h3><p>The main idea is that in addition to the actual data, we store some per-element metadata and a <em>sentinel</em> that guards some of the data, switching it off conditionally. In this case, we store per-element “timestamps”:<pre><code class=language-rust><span class=hljs-keyword>struct</span> <span class="hljs-title class_">ArrayWithGlobalAssignment</span>&LTT, <span class=hljs-keyword>const</span> N: <span class=hljs-type>usize</span>> {
It is not a novel technique by any means, but it doesn’t seem on everyone’s lips, so some of you might find it interesting."property=og:description><meta content=en_US property=og:locale><meta content="purplesyringa's blog"property=og:site_name><meta content=summary_large_image name=twitter:card><meta content=https://purplesyringa.moe/blog/the-sentinel-trick/og.png name=twitter:image><body><header><div class=viewport-container><div class=media><a href=https://github.com/purplesyringa><img src=../../images/github-mark-white.svg></a></div><h1><a href=/>purplesyringa</a></h1><nav><a href=../..>about</a><a class=current href=../../blog/>blog</a><a href=../../sink/>kitchen sink</a></nav></div></header><section><div class=viewport-container><h2>The sentinel trick</h2><time>August 13, 2024</time><p>The sentinel trick underlies a data structure with the following requirements:<ul><li>Read element by index in <eq><math><mrow><mi>O</mi><mo form=prefix stretchy=false>(</mo><mn>1</mn><mo form=postfix stretchy=false>)</mo></mrow></math></eq>,<li>Write element by index in <eq><math><mrow><mi>O</mi><mo form=prefix stretchy=false>(</mo><mn>1</mn><mo form=postfix stretchy=false>)</mo></mrow></math></eq>,<li>Replace all elements with a given value in <eq><math><mrow><mi>O</mi><mo form=prefix stretchy=false>(</mo><mn>1</mn><mo form=postfix stretchy=false>)</mo></mrow></math></eq>.</ul><p>It is not a novel technique by any means, but it doesn’t seem on everyone’s lips, so some of you might find it interesting.<h3>Why?</h3><p>We could just use a hashmap and store a “default” value. Clearing a hashmap requires no more time than writes do, so the amortized time is <eq><math><mrow><mi>O</mi><mo form=prefix stretchy=false>(</mo><mn>1</mn><mo form=postfix stretchy=false>)</mo></mrow></math></eq> for all three operations.<p>But hashmaps are notoriously slow. If I want an array, I don’t want random access all around my too-large-to-fit-into-cache data.<p>The sentinel trick provides <code>clear</code> for arrays.<h3>How?</h3><p>The main idea is that in addition to the actual data, we store some per-element metadata and a <em>sentinel</em> that guards some of the data, switching it off conditionally. In this case, we store per-element “timestamps”:<pre><code class=language-rust><span class=hljs-keyword>struct</span> <span class="hljs-title class_">ArrayWithGlobalAssignment</span>&LTT, <span class=hljs-keyword>const</span> N: <span class=hljs-type>usize</span>> {
local: [(T, <span class=hljs-type>usize</span>); N],
global: T,
sentinel: <span class=hljs-type>usize</span>,
Expand Down
Loading

0 comments on commit d4b75bf

Please sign in to comment.