ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
crc32.c
Go to the documentation of this file.
1
7#include <ascii-chat/network/crc32.h>
8#include <ascii-chat/platform/system.h>
9#include <string.h>
10#include <stdio.h>
11#include <stdatomic.h>
12
13// Multi-architecture hardware acceleration support
14#if defined(__aarch64__)
15#include <arm_acle.h>
16#define ARCH_ARM64
17#elif defined(__x86_64__) && defined(HAVE_CRC32_HW)
18#include <immintrin.h>
19#ifdef _WIN32
20#include <intrin.h>
21#else
22#include <cpuid.h>
23#endif
24#define ARCH_X86_64
25#endif
26
27// Check if CRC32 instructions are available at runtime
28static bool crc32_hw_available = false;
29static atomic_bool crc32_hw_checked = false;
30
31static void check_crc32_hw_support(void) {
32 // Fast path: check if already initialized (atomic read)
33 if (atomic_load(&crc32_hw_checked)) {
34 return;
35 }
36
37 // Try to claim initialization (only one thread will succeed)
38 bool expected = false;
39 if (!atomic_compare_exchange_strong(&crc32_hw_checked, &expected, true)) {
40 // Another thread is initializing or already initialized, wait for it
41 // Add backoff sleep to prevent 100% CPU burn if init thread is preempted
42 int spin_count = 0;
43 while (!atomic_load(&crc32_hw_checked)) {
44 spin_count++;
45 if (spin_count > 100) {
46 // After 100 spins, sleep briefly to avoid CPU waste
47 platform_sleep_us(1); // Sleep 1 microsecond (Windows rounds up to 1ms)
48 spin_count = 0;
49 }
50 }
51 return;
52 }
53
54 // This thread won the race and will perform initialization
55
56 // clang-format off
57#ifdef ARCH_ARM64
58// On Apple Silicon, CRC32 is always available
59// On other ARM64 systems, we could check HWCAP_CRC32
60#ifdef __APPLE__
61 crc32_hw_available = true;
62#else
63 // For other ARM64 systems, we'd need to check auxiliary vector
64 // For now, assume available (can be made more sophisticated)
65 crc32_hw_available = true;
66#endif
67 // log_debug("ARM CRC32 hardware acceleration: %s", crc32_hw_available ? "enabled" : "disabled");
68#elif defined(ARCH_X86_64)
69 // Check for SSE4.2 support (includes CRC32 instruction)
70#ifdef _WIN32
71 int cpu_info[4];
72 __cpuid(cpu_info, 1);
73 // SSE4.2 is bit 20 of ECX
74 crc32_hw_available = (cpu_info[2] & (1 << 20)) != 0;
75#else
76 unsigned int eax, ebx, ecx, edx;
77 if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
78 crc32_hw_available = (ecx & bit_SSE4_2) != 0;
79 } else {
80 crc32_hw_available = false;
81 }
82#endif
83 // log_debug("Intel CRC32 hardware acceleration (SSE4.2): %s", crc32_hw_available ? "enabled" : "disabled");
84#else
85 crc32_hw_available = false;
86 // log_debug("No hardware CRC32 acceleration available for this architecture");
87#endif // clang-format on
88
89 // Initialization complete - flag was already set to true by atomic_compare_exchange_strong above
90 // The compare-exchange with memory_order_seq_cst ensures all writes to crc32_hw_available
91 // are visible to other threads when they see crc32_hw_checked == true
92}
93
94#ifdef ARCH_ARM64
95// ARM CRC32-C hardware implementation using Castagnoli polynomial
96// IMPORTANT: Use __crc32cb (CRC32-C) NOT __crc32b (IEEE 802.3)
97// __crc32cb uses the Castagnoli polynomial (0x1EDC6F41), matching:
98// - Intel _mm_crc32_* intrinsics
99// - Our software fallback asciichat_crc32_sw()
100// Process byte-by-byte to ensure cross-platform consistency with x86
101__attribute__((target("arch=armv8-a+crc"))) static uint32_t crc32_arm_hw(const void *data, size_t len) {
102 const uint8_t *bytes = (const uint8_t *)data;
103 uint32_t crc = 0xFFFFFFFF;
104
105 // Process all bytes one at a time for guaranteed consistency
106 // Use CRC32-C intrinsics (__crc32cb) not CRC32 (__crc32b)
107 for (size_t i = 0; i < len; i++) {
108 crc = __crc32cb(crc, bytes[i]);
109 }
110
111 return ~crc;
112}
113#endif
114
115#ifdef ARCH_X86_64
116// Intel CRC32 hardware implementation using SSE4.2
117// Process byte-by-byte to ensure cross-platform consistency with ARM
118static uint32_t crc32_intel_hw(const void *data, size_t len) {
119 const uint8_t *bytes = (const uint8_t *)data;
120 uint32_t crc = 0xFFFFFFFF;
121
122 // Process all bytes one at a time for guaranteed consistency
123 for (size_t i = 0; i < len; i++) {
124 crc = _mm_crc32_u8(crc, bytes[i]);
125 }
126
127 return ~crc;
128}
129#endif
130
131// Multi-architecture hardware-accelerated CRC32
132uint32_t asciichat_crc32_hw(const void *data, size_t len) {
133 check_crc32_hw_support();
134
135 if (!crc32_hw_available) {
136 // DEBUG: Log fallback to software
137 static bool logged_fallback = false;
138 if (!logged_fallback) {
139 log_debug("Using software CRC32 (no hardware acceleration)");
140 logged_fallback = true;
141 }
142 return asciichat_crc32_sw(data, len);
143 }
144
145#ifdef ARCH_ARM64
146 static bool logged_arm = false;
147 if (!logged_arm) {
148 log_debug("Using ARM64 hardware CRC32");
149 logged_arm = true;
150 }
151 return crc32_arm_hw(data, len);
152#elif defined(ARCH_X86_64)
153 static bool logged_intel = false;
154 if (!logged_intel) {
155 log_debug("Using Intel x86_64 hardware CRC32 (SSE4.2)");
156 logged_intel = true;
157 }
158 return crc32_intel_hw(data, len);
159#else
160 return asciichat_crc32_sw(data, len);
161#endif
162}
163
165 check_crc32_hw_support();
166 return crc32_hw_available;
167}
168
169// Software fallback implementation using CRC32-C (Castagnoli) polynomial
170// This matches the hardware implementations (__crc32* and _mm_crc32_*)
171uint32_t asciichat_crc32_sw(const void *data, size_t len) {
172 const uint8_t *bytes = (const uint8_t *)data;
173 uint32_t crc = 0xFFFFFFFF;
174
175 // CRC32-C (Castagnoli) polynomial: 0x1EDC6F41
176 // Reversed (for LSB-first): 0x82F63B78
177 for (size_t i = 0; i < len; i++) {
178 crc ^= bytes[i];
179 for (int j = 0; j < 8; j++) {
180 if (crc & 1) {
181 crc = (crc >> 1) ^ 0x82F63B78; // CRC32-C polynomial (reversed)
182 } else {
183 crc >>= 1;
184 }
185 }
186 }
187
188 return ~crc;
189}
__attribute__((constructor))
Register fork handlers for common module.
Definition common.c:104
bool crc32_hw_is_available(void)
Definition crc32.c:164
uint32_t asciichat_crc32_sw(const void *data, size_t len)
Definition crc32.c:171
uint32_t asciichat_crc32_hw(const void *data, size_t len)
Definition crc32.c:132
void platform_sleep_us(unsigned int us)