Blog
Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.
Text'i Doğru İşlemek: Normalization, Mojibake Teşhisi ve Base64
Aynı görünen iki string eşit olmayabilir çünkü "ş" hem tek code point (NFC) hem s + birleşen işaret (NFD) olarak yazılabilir; çözüm text'i sistemin sınırında NFC'ye getirmek. NFKC ile arama anahtarı, culture'a göre değişen arama, "ÅŸ" gibi mojibake'i hex dump ile teşhis edip onarmak, CSV/Excel BOM'u, HTTP charset, SQL Server'da N prefix'i ve UTF-8 collation, Base64/Base64Url ve JWT'nin neden şifreli olmadığı.
Unicode ve UTF-8/UTF-16: Code Point, Surrogate Pair, Rune ve Emoji'de Bozulan string.Length
string.Length emojide bozulur çünkü .NET ve JavaScript string'i UTF-16 code unit olarak sayar; aile emojisi tek bir grapheme ama 5 code point, 8 code unit ve 18 UTF-8 byte'tır. ASCII'den Unicode'a, code point, plane ve scalar value, UTF-8 ve surrogate pair'i elle encode etmek, Rune, u8 literal ve BOM, StringInfo ve Intl.Segmenter ile 280 karakterlik yorum sınırını doğru saymak.
Floating Point Nasıl Çalışır: IEEE 754, 0.1 + 0.2, NaN ve double vs decimal
0.1 + 0.2, 0.3 etmez çünkü double sayıları 2 tabanında sign, exponent ve 52 bitlik mantissa ile tutar ve 0.1 bu tabanda tam yazılamaz. binary64'ün bit düzeni, sayılar büyüdükçe açılan boşluklar, ±0, NaN ve subnormal, relative tolerance ile karşılaştırma, Half/float/double/decimal farkı, .NET 9 ve .NET 11'in saturating dönüşümleri, banker's rounding ve culture'a bağlı parse.
Integer Temsili: Two's Complement, Overflow, Endianness ve JSON'da Kaybolan long ID
Bilgisayar negatif integer'ları two's complement ile tutar: bitleri çevirip 1 eklersin, böylece tek bir toplayıcı hem toplar hem çıkarır ve tek bir sıfır kalır. int.MinValue asimetrisi ve Math.Abs exception'ı, wrap-around, byte'tan Int128'e genişlikler, endianness ve BinaryPrimitives, 2^53'ü geçen long ID'nin JSON'da sessizce değişmesi, Y2038 ve tükenen int identity.
Bitwise İşlemler: AND, OR, XOR, Shift ve Bit Mask ile Flag Yönetimi
Bitwise operatörler iki sayının aynı konumdaki bitlerini ayrı ayrı işler; AND filtreler, OR ekler, XOR çevirir, shift kaydırır. Bookstore izinlerini tek bir integer'da set/clear/toggle/test etmek, BitOperations, C# 11 >>> operatörü, shift miktarının maskelenmesi ve TypeScript'in her bitwise işlemi 32 bite indirip büyük ID'leri sessizce bozması.
Binary ve Hexadecimal: Positional Notation, Bit, Byte ve Dönüşümler
Hex, her iki karakteri tam bir byte'a denk geldiği için binary'nin kısa yazımıdır: dört bit bir hex basamağıdır. Positional notation, elle dönüşüm, C# ve TypeScript literal'leri ve format'ları, renk kodu, GUID, hash ve magic number okumak, 500 GB'lık diskin Windows'ta neden 465 GB göründüğü.
SIMD ve Vectorization: Vector128, Vector256, Vector512 ve TensorPrimitives ile Aynı Anda Çok Veri
SIMD, tek bir instruction ile geniş bir register'daki 4, 8 ya da 16 değeri aynı anda işlemektir; .NET'te bunu BCL, TensorPrimitives, Vector<T> ve Vector128/256/512 katmanlarıyla kullanırsın. Bir milyon int toplamda tek accumulator'lı vector döngüsü 2 kat, dört accumulator'lı olan 6,5 kat hızlı; x64 assembly'de vpaddd ymm/zmm, IsHardwareAccelerated'ın JIT sabiti olması ve double toplamın donanıma göre değişmesi.
Multi-Core, Hyper-Threading ve False Sharing: Çekirdek Sayısı Neden Performansı Doğrusal Artırmaz?
Çekirdek sayısı performansı doğrusal artırmaz, çünkü core'lar cache line, bellek bant genişliği ve execution unit gibi kaynakları paylaşır. Dört worker'lık Bookstore sayacında paylaşılan Interlocked sayacın 15 kat yavaşlaması, yan yana slot'ların false sharing yüzünden tek thread'i geçememesi, padding ve local değişkenle düzeltme, Environment.ProcessorCount'un container limitine göre değişmesi ve Hyper-Threading ile P/E core'ların etkisi.
CPU Cache Nasıl Çalışır: Cache Line, Associativity ve Cache-Friendly C# Kodu
CPU bellekten byte değil cache line okur (x64'te 64 byte) ve bir adresi tag, index ve offset'e bölüp tek bir set'te arar; kodun hızı bu düzene uyup uymamasına bağlıdır. 4096 × 4096 tabloyu sütun sütun gezmenin 6,5 kat yavaşlığı, genişliği 16 artırınca conflict miss'in kalkıp döngünün 4,6 kat hızlanması, Struct of Arrays ile 5 kat kazanç ve field sırasıyla 40 byte'tan 24 byte'a inen struct.
Memory Hierarchy: Register'dan SSD'ye Latency Rakamları ve Locality
Bellek tek parça değildir: register ve L1'den DRAM'e, SSD'ye ve network'e indikçe her katman büyür ve yavaşlar; bir DRAM okuması L1'den yaklaşık 90 kat uzun sürer. 256 MB'lık bir array'i karışık sırayla toplamanın 13,4 kat yavaşlaması, pointer chasing ile kendi makinende latency ölçmek, stack ile heap'in aynı RAM olması ve struct array'in List<Book>'tan 6 kat hızlı taraması.
CPU Pipeline ve Branch Prediction: Sıralı Array Neden Daha Hızlı İşlenir?
Sıralı array daha hızlı işlenir çünkü içindeki if'ler tahmin edilebilir hâle gelir ve CPU pipeline'ı boşaltmak zorunda kalmaz. Bir milyon siparişte 9,4 kat fark, JIT'in döngüde neden cmov üretmediği, bit mask ile branchless toplama, bağımlılık zinciri ve ILP, Spectre'nin neden var olduğu.
Bir C# Satırı CPU'da Nasıl Çalışır: Kaynak Koddan IL'e, Assembly'den Instruction'a
Bir C# satırı CPU'ya iki çeviriyle ulaşır: Roslyn onu IL'e, JIT de çalışma anında o makinenin ISA'sına göre machine code'a çevirir; CPU bu byte'ları fetch-decode-execute döngüsüyle işler. TotalQuantity'nin 30 byte'lık x64 Tier-1 kodunu satır satır okuyor, ARM64 karşılığıyla, 789 byte'lık decimal versiyonuyla ve optimizasyonsuz Tier-0 ölçümüyle karşılaştırıyor, .NET 11'in x86-64-v2 tabanını anlatıyoruz.