C++ och dess framtid att programmera minnessäkert - Hur går utvecklingen?

Permalänk
Medlem
Skrivet av Yoshman:

Du har redan fått konkret exempel på fall där samma imperativa logik blir väldigt mycket snabbare med en GC jämfört med C++, kanske på plats med sanna konkreta exempel på varför GC är så mycket långsammare?

Det här uttalandet förstår inte jag. Du vet själv hur assembler fungerar. Du (och jag) kan lätt granska vad det som sker under ytan och du och jag vet hur svårt det är att göra någon större skillnad i mindre lösningar.

Skulle man se stora skillnader i prestanda så är det inte samma funktionalitet, det kan man lätt räkna ut.

Hade jag gjort prestandatest mellan olika språk och sett kanske dubbelt eller mer i skillnad i hastighet och jag vet att språken kompileras till maskinkod. Då är min första tanke att jag har olika kod, de gör olika saker. Den nivån vi jämför mellan olika här är för liten.

Skrivet av Yoshman:

(Och, nej din video duger inte då arena-allokator är absolut inte unikt för C++ utan går med fördel att göra även om man har en GC)

Kodar Rust utvecklare på det viset? Jag har inte sett det. Koden blir för "jobbig". Jag vet definitivt att denna typ av kod (själv skapa ett block och sköta det internt) inte existerar bland C# utvecklare. Skulle någon få för sig att skriva sådan kod är jag helt övertygad om att utvecklaren får kasta bort det.
Har jobbat med en hel del del C# utvecklare. Det är STOR skillnad i hur kod skrivs. Du får inte skena iväg och skriva för svårt. Och det skulle förvåna om det är tillåtet bland utvecklare i Rust.

Dessa "säkra" språk är inte gjorda för att leka med minnet. När det blir större och mer komplexa har de för länge sedan lämnat walk over. Koden blir för jobbig.

Permalänk
Medlem
Skrivet av mc68000:

Tänker du på kompilatoroptimering här? Det är ju stor skillnad på -O1 och -O3, för du kör väl med optimering? Eller kör du utan optimering; för att det ger bättre kontroll på vilken assembler som genereras utifrån hur du skriver din kod?

Ja, kompilatoroptimering har ökat i betydele och att man lär sig skriva koden så kompilatorn lätt kan optimera koden

Skrivet av mc68000:

När du jämför språken, hur ställer du dig till att kompilatorerna har gemensam backend för flera språk med gemensam optimering.

Jag gissar på att LLVM varit en räddning för många äldre språk. Med den kompilatorn räcker det med att göra om språket till det mellanformat som LLVM använder när kod genereras och de slipper underhålla egna kompilatorer. För det tror jag är ett övermäktigt jobb idag. LLVM tror jag också är en stor orsak till att så många nya språk dykt upp och kunnat samla utvecklare och ganska snabbt vara konkurrenskraftiga.
Personligen tror jag inte denna trend kommer minska utan tvärtom blir det fler och fler språk. Det finns så många utvecklare som älskar att skriva egna språk så det är svårt att hindra.
Och andra kompilatorer kanske också lägger till logik som liknar LLVM.

Att det kommer har enligt mig med AI och göra. De bästa utvecklarna i dessa områden kan bli så mycket mer produktiva.

Skrivet av mc68000:

Precis som COBOL och FORTRAN idag har blivit nischade i bank- respektive den akademiska världen så utsätts språken ständigt för ökade krav. I C får man snällt handkoda för de finesser som efterfrågas på dagens moderna marknad, medans C++ möter detta med att återigen införa utökningar i språket. Evolutionen går vidare och ideer och tankesätt flödar ständigt mellan språken.

Spekulerar men jag tror banker sitter fast en del i äldre system och möjligen kan det ha och göra med att det är personer där med höga löner som inte vill släppa fram nya förmågor, samt att de också kan ha svårt att locka unga intresserade utvecklare. Miljön är inte så sexig.
Banker konkurrerar inte med bra mjukvara och det spelar för dem mindre roll hur det görs så länge det fungerar. Banker skiter i sina kunder som de flesta vet om.
Kan tänka mig att det är samma i den akademiska världen, lärare som sitter fast där och det blir segt med ändringar

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

Hur påverkas din bild av att inget får göras under ytan när man slår på optimering? Loop invariant code motion flyttar exempelvis ut kod ur en loop. Koden som lyfts ut är inget du har bett om att det skall evalueras före loopen. Common sub expression kan flytta kod långt. Det är också kod som kommer evalueras på ett ställe där du inte har bett om det.

Tror du möjligen misstolkat mig. När jag menar att inget får göras under ytan så handlar det om extra funktionalitet, saker som bäddas in för att klara av att lösa något.
Om vi tar extremfallet python (som är interpreterande och inte alls har med det här att göra). Där händer massor och de vet om det.

Att det optimeras mer eller till och med rensas bort är ofta önskat
Medan C# lösningen för reflection hade varit omöjlig i C++ för att ta ett annat exempel

Permalänk
Medlem
Skrivet av klk:

Banker konkurrerar inte med bra mjukvara och det spelar för dem mindre roll hur det görs så länge det fungerar.

Mjukvara som fungerar är bra mjukvara.

Jag är helt övertygad om att du inte har skapat någonting överhuvudtaget.

Jag gillar egentligen inte att göra det personligt, men jag tror att du är ganska ensam på din arbetsplats, om du har någon sådan, och att alla andra ser på dig lite som en "goofball" med tveksamma "social skills".
Och att det bara gör dig mer övertygad om att du har rätt och att alla andra har fel/är idioter.

Och historiskt finns såklart såna exempel, Copernicus Dan Shechtman för att nämna några (även om Copernicus' slutsatser idag är tveksamma).

Så jag tror att du argumenterar lika mycket för dig själv och din dåliga självkänsla som mot andra.

Skrivet av klk:

...och möjligen kan det ha och göra med att det är personer där med höga löner som inte vill släppa fram nya förmågor,...

Det här är väl "du". Du har ingenting emot yngre förmågor så länge dom gör exakt samma sak som du.

Men om jag kom till "dig" och sa att jag kan göra exakt samma sak i språk X och med exakt samma sak menar jag att resultatet är exakt samma.
Vägen dit, språket, är såklart annorlunda så skulle du säga nej, baserat på fördomar och okunskap.

Fördelen med språk X är, bland annat, att det är ett modernare språk, där det betydligt enklare att hitta utvecklare, och nackdelen är såklart att det gör dig obsolete.

Permalänk
Medlem
Skrivet av Xeonist:

Mjukvara som fungerar är bra mjukvara.

Jag är helt övertygad om att du inte har skapat någonting överhuvudtaget.

Helt ok, du får självklart tro vad du vill

Skrivet av Xeonist:

Men om jag kom till "dig" och sa att jag kan göra exakt samma sak i språk X och med exakt samma sak menar jag att resultatet är exakt samma.
Vägen dit, språket, är såklart annorlunda så skulle du säga nej, baserat på fördomar och okunskap.

Men jag har frågat flera gånger i tråden, kan ni visa där andra utvecklare i exempelvis C# eller Rust skriver sådan kod som ni använder här för att visa
Jag har letat men inte hittat

Permalänk
Skrivet av klk:

Tror du möjligen misstolkat mig. När jag menar att inget får göras under ytan så handlar det om extra funktionalitet, saker som bäddas in för att klara av att lösa något.

Låt oss ta address sanitizer som exempel. Där lägger kompilatorn till extra funktionalitet för spårning av objekt och kontrollerar att accesserna håller sig inom de allokerade objekten. Slutar det vara ett C++-program för att kompilatorn stoppar in "extra" funktionalitet i den genererade koden?

Permalänk
Medlem
Skrivet av klk:

Kodar Rust utvecklare på det viset? Jag har inte sett det.

Har du testat att Googla "rust arena allocator"? https://github.com/fitzgen/bumpalo

Du har redan fått ett svar om arena-allokator inte passar alla scenarion så det är dumt att anta att merparten skulle använda det. Bumpalo har laddats ner 25,779,702 de senaste 90 dagarna så det är inte ett helt outnyttjat fall.

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

Låt oss ta address sanitizer som exempel. Där lägger kompilatorn till extra funktionalitet för spårning av objekt och kontrollerar att accesserna håller sig inom de allokerade objekten. Slutar det vara ett C++-program för att kompilatorn stoppar in "extra" funktionalitet i den genererade koden?

Du skulle ju aldrig skeppa ett program som bäddat in kod från address sanitizer, så länge man kompilerar olika versioner för att lättare hitta buggar så spelar det ingen roll. Kompilerar jag i debug så är det en hel massa som bäddas in för att kontrollera och även mängder med "onödig" kod. Allt är för att slipa slutresultatet och det är där saker inte får ligga och skräpa.

Permalänk
Datavetare
Skrivet av klk:

Det här uttalandet förstår inte jag. Du vet själv hur assembler fungerar. Du (och jag) kan lätt granska vad det som sker under ytan och du och jag vet hur svårt det är att göra någon större skillnad i mindre lösningar.

Skulle man se stora skillnader i prestanda så är det inte samma funktionalitet, det kan man lätt räkna ut.

Självklart är det inte identisk funktionalitet, behövs inte assembler-analys för att fatta det. En använder GC och en använder manuell minneshantering t.ex. via RAII.

Grejen är att om man har fall där man frekvent behöver allokera minne så har en GC en fördel, by-design, i att dess allokeringslogik kan med fördel göras så den är lika snabb som en typisk arena-allokator. Och likt hur man optimerar högpresterande I/O-trafik, coalescing (många små väldigt snarlika uppgifter kombineras till en större), får GC, by-design, just ett sådant beteende i sin av-allokeringslogik.

"C++ programmerare löser detta just med arena-allokator" kanske är din invändning. Sure, om alla allokerade objekt har en begränsad och väldefinierad livslängd som är praktiskt användbar. Men inte alls ovanligt att ha fall där de flesta objekt har en relativt kort livslängd, medan vissa lever längre. Det kopplat med att det inte är möjligt att veta vilka som lever längre i förväg ger en klart prestandafördel till GC i ett inte alls osannolikt real-world use-case.

"Objekt" är här "minnesobjekt", inte objekt i typiskt OOP-sense.

Ovanpå detta finns en annan optimering som i alla fall JVM-språk och Go använder sig av frekvent relaterad till effektiv minneshantering: escape analysis.

Det kan också resultera i "högre prestanda än logiskt ekvivalent C++" då vissa heap-allokeringar kan ersättas med stack-allokeringar. Det kan i teorin (är inte hundra på om det görs i praktiken) spekulativt i fall där vissa vägar tillåter stack-allokering, medan andra låter objektet "rymma" och i det läget måste man flytta data till heap (logiskt är detta sätt att skriva kod idiomatiskt i Go, i.e. man allokerar på stacken och returnerar en pekare till data, känns fel som C/C++ programmerare då det är en inte helt sällsynt bug med rätt stora säkerhetsimplikationer...)

TL;DR Det finns absolut fall där GC kan vara mer effektivt jämfört med manuell minneshantering. Självklart finns också fall där manuell minneshantering kan vara effektivare än GC.

Skrivet av klk:

Kodar Rust utvecklare på det viset? Jag har inte sett det. Koden blir för "jobbig". Jag vet definitivt att denna typ av kod (själv skapa ett block och sköta det internt) inte existerar bland C# utvecklare. Skulle någon få för sig att skriva sådan kod är jag helt övertygad om att utvecklaren får kasta bort det.
Har jobbat med en hel del del C# utvecklare. Det är STOR skillnad i hur kod skrivs. Du får inte skena iväg och skriva för svårt. Och det skulle förvåna om det är tillåtet bland utvecklare i Rust.

Dessa "säkra" språk är inte gjorda för att leka med minnet. När det blir större och mer komplexa har de för länge sedan lämnat walk over. Koden blir för jobbig.

Varför skulle man inte göra så i Rust vid behov? En huvudanledning att använda Rust är just för man vill/behöver manuell minneshantering, t.ex. hård realtid.

Så här krångligt är det att använda en arena allokator. bumparo projektet hanteras av Alex Crichton och Nick Fitzgerald, båda är välkända profiler i Rust-världen, båda har bl.a. jobbat med standardbiblioteket i Rust.

Notera också att projektet har totalt 157M nedladdningar, så det är hyfsat populär crate.

Klicka för mer information

use bumpalo::Bump; #[derive(Debug)] struct Person { name: String, age: u8, } fn with_arena_allocator() { let arena = Bump::new(); let mut persons = bumpalo::collections::Vec::new_in(&arena); persons.push(Person { name: "Arena Alice".to_string(), age: 30, }); persons.push(Person { name: "Arena Bob".to_string(), age: 40, }); for person in persons.iter() { println!("{:?}", person); } } fn with_heap_allocator() { let mut persons = Vec::new(); persons.push(Person { name: "Heap Alice".to_string(), age: 30, }); persons.push(Person { name: "Heap Bob".to_string(), age: 40, }); for person in persons.iter() { println!("{:?}", person); } } fn main() { with_arena_allocator(); with_heap_allocator(); }

Visa mer

Och varför skulle inte C#-kod använda arena-allokator. Ser mig inte som en "C#-programmerare", finns flera språk jag föredrar över C#, men för tillfället sitter jag primärt just i C# på jobbet, i ett projekt som har en custom-designed arena-allokator inkluderat (använder C# för enda realistiska alternativen var C++ eller C#, hade hellre använt Go men fungerar tyvärr inte).

Men finns också arena-allokator alternativ på NuGet, t.ex. Varena.

Kanske sluta göra antaganden om brister och "vad som inte kan göras" i miljöer du aldrig använt?

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem
Skrivet av orp:

Har du testat att Googla "rust arena allocator"? https://github.com/fitzgen/bumpalo

Du har redan fått ett svar om arena-allokator inte passar alla scenarion så det är dumt att anta att merparten skulle använda det. Bumpalo har laddats ner 25,779,702 de senaste 90 dagarna så det är inte ett helt outnyttjat fall.

Har googlat på en hel del och även "pratat" med olika AI verktyg. Jag vet ju att om jag skulle lämna "luckor" så blir jag sågad vid fotknölarna med en gång

Vad jag inte förstår är hur man i Rust skulle kunna hantera block med minne och samtidigt få säkerhet utan att gå utanför blockets gränser med smidigare kod än exempelvis C++.

Repeterar att jag självklart vet att det går. Problemet är att språken inte är gjorda för det och det ser genast mycket konstigt ut. I alla fall där jag lyckats hitta något som liknar. Och eftersom det är det enda jag hittat så finns det ingen poäng för C/C++ utvecklare att byta till miljö som är krångligare och inte alls har samma ekosystem.

Så svårt är det heller inte att se på kod eller hur någon löser problem för att förstå vad som är möjligt.

Vi har ju diskuterat imperativ kontra deklarativ kod (vet att du och jag tycker olika). Men eftersom det är färskt då jag nyligen haft diskussion om det. Så kan jag ta ett ganska enkelt exempel som visar hur en ganska enkel lösning snabbt blir kaos eftersom den inte är byggd för det.

En websida skall göra. Websidan kommer hantera 10 kommandon (anrop) för att göra det enkelt. Och skall sidan få lov och skicka anropen till servern måste det vara av inloggad användare.

Sidan måste nu ha två state: 1) användare är inte inloggad, 2) användare är inloggad
Än så länge är det inga problem, här är det nästan bara att släcka ner det mesta för icke inloggad användare.

Sidan behöver marknadsföras och det bör vara möjlighet att testa sidan.
Ett till state införs och det är "gäst".
Sidan kan nu ha tre olika state (inte inloggad, gäst, användare).
De 10 olika kommandona blir något rörigare då flera där fungerar olika beroende på sidans state.

Så kommer ett fjärde state, nu är det superuser. 4 olika state på en ganska enkel html sida som nu plötsligt inte är lika enkel längre.

Vad vill jag säga med ovanstående.
Om man är van vid att endast göra enkla saker, kanske skriva ihop något för att lösa problem och knappt någon annan kommer titta på det eller att man har en begränsad del i ett system där det mest är underhåll. Då är ovanstående "okänt".
Men om ett större system skall skrivas och de inte exakt vet alla krav mer än på ett ungefär. Då kan en prototyp vara enkel och få fram men små förändringar kan göra att det snabbt blir mycket svårt.

I den här tråden diskuterar vi säkerhetsproblem på grund av minnet. Nästan som att det inte finns något annat.

Skall jag vara med och sätta arkitekturen på ett större system så hamnar minnesproblematik långt ner på listan. Det finns så mycket annat så är så mycket svårare. Även om det inte blir säkerhetsproblem av buggar där man rört ihop det så är det ändå irriterade kunder och det är lika allvarligt det.

Klarar inte utvecklare en arkitektur där minnet sköts även om det görs för "hand", så hur skall den utvecklare klara att hantera komplexa situationer med state?

Permalänk
Skrivet av klk:

Att ha alla strängar i ett enda block är bra för lokalitet och att det blir ett allokeringsanrop istället för 10 eller mer. När allt ligger i ett block fungerar processorn som bäst och då går det mycket snabbare.

Jag saxar detta guldkorn från gårdagens bataljer.

Att bli av med 9 anrop till allokeringsfunktionen är definitivt en vinst, men det påverkar väl inte processorn i sig? Skulle du kunna utveckla vad det är som fungerar bättre när de 10 strängarna ligger i samma block? Är det någon speciell funktionsenhet i CPU som fungerar bättre eller har du antagit ett holistiskt synsätt?

Du specade ju explicit att strängarna skulle ha alignment så de passade för SIMD-instruktioner. Optimerar vi för AVX512 sammanfaller det med en cache-line, så du lär ju inte se några vinster där.

Prefetching, ja, möjligen, men då måste strängarna vara långa och du får i stort sett bara läsa ut dem back-to-back och inte göra så mycket däremellan för annars bryter du lineariteten i accesserna.

Lokalitet, tja, om du allokerar 10 strängar direkt efter varandra är det då sannolikt att minnet där strängarna sparas ligger i direkt anslutning till varandra?

Vad i processorn fungerar bättre när strängarna ligger i samma block? Använd gärna vedertagen datorsystemsarkitekturterminologi. Om det skall gå "mycket snabbare" så pratar vi väl om något mer än enstaka extra cache-missar?

Permalänk
Medlem
Skrivet av klk:

Helt ok, du får självklart tro vad du vill

När du svarar så då bekräftar du bara för mig att min åsikt stämmer.

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

Skulle du kunna utveckla vad det är som fungerar bättre när de 10 strängarna ligger i samma block?

prefetchers fungerar så mycket bättre om minnet hänger samman. När processorn läser minne så chansar processorn och läser extra mycket. Låt säga att processorn läser från adress 100, det är bara ett värde från adressen som läses in och det är kanske 4 byte. Men processorn läser inte bara dessa 4 byte utan den läser minst 64 byte (x86,ARM). Minst en cache line som är 64 byte. Vet man det så vet utvecklaren att det ligger mer minne i L1 cache och den är blixtsnabb.
Kan man hålla samman information till olika block så här så kan man få träff i L1 hela tiden då processor förladdar minne.

Gör du tvärtom så att det är 10 olika adresser. Måste man vandra igenom varje sträng behöver processorn gå till ny adress och det kan i värsta fall innebära att den behöver gå till ram. Samtidigt som den går till ram kan den behöva kasta bort minne som är laddat i L1 cachen (den är inte så stor).

Skillnaden på de här två sätten att hantera minne blir ofta större än vad man tror, speciellt som desto mer processorn jobbar desto större skillnader. Orsaken är att när processorn jobbar hårt jobbar den ofta med mycket minne och då måste mer kastas bort och laddas om.
Därför så när man gör enkla prestandatest kan de se snabbt ut även om strängarna ligger på olika adresser. Plötsligt körs samma kod på en tungt belastad server och det går inte alls så snabbt.

För att beskriva med en annan processor- Intels core 2 duo. Jättesvår processor och benchmarka. Intel la in mycket stort och snabbt L2 cache i den. En enkeltrådad applikation, där kunde den snabbt ladda in allt i cachen och då gick det undan.
Att simulera en tungt belastad processor är svårt så många förundrades över hur snabb processorn var.

När processorn sedan användes så stämde det inte, bara den fick jobba lite hårdare så dog den (nästan). Kärnorna var långsamma på att kommunicera och fanns inte minnet i L2 cachen så gick det mycket långsammare.

SIMD:
För att simd instruktioner skall fungera måste minnet ligga i cache. Jag tror det är ett krav och allt måste ligga där. Ligger det inte i cache fungerar inte operationen och då går den ner till att tugga varje instruktion var för sig.
AMDs 9000 model kan köra AVX 512 i full fart. Skrivs koden för detta så är det mycket snabbare än att beta av instruktion för instruktion.

Permalänk
Datavetare
Skrivet av klk:

prefetchers fungerar så mycket bättre om minnet hänger samman. När processorn läser minne så chansar processorn och läser extra mycket. Låt säga att processorn läser från adress 100, det är bara ett värde från adressen som läses in och det är kanske 4 byte. Men processorn läser inte bara dessa 4 byte utan den läser minst 64 byte (x86,ARM). Minst en cache line som är 64 byte. Vet man det så vet utvecklaren att det ligger mer minne i L1 cache och den är blixtsnabb.
Kan man hålla samman information till olika block så här så kan man få träff i L1 hela tiden då processor förladdar minne.

Gör du tvärtom så att det är 10 olika adresser. Måste man vandra igenom varje sträng behöver processorn gå till ny adress och det kan i värsta fall innebära att den behöver gå till ram. Samtidigt som den går till ram kan den behöva kasta bort minne som är laddat i L1 cachen (den är inte så stor).

Skillnaden på de här två sätten att hantera minne blir ofta större än vad man tror, speciellt som desto mer processorn jobbar desto större skillnader. Orsaken är att när processorn jobbar hårt jobbar den ofta med mycket minne och då måste mer kastas bort och laddas om.
Därför så när man gör enkla prestandatest kan de se snabbt ut även om strängarna ligger på olika adresser. Plötsligt körs samma kod på en tungt belastad server och det går inte alls så snabbt.

För att beskriva med en annan processor- Intels core 2 duo. Jättesvår processor och benchmarka. Intel la in mycket stort och snabbt L2 cache i den. En enkeltrådad applikation, där kunde den snabbt ladda in allt i cachen och då gick det undan.
Att simulera en tungt belastad processor är svårt så många förundrades över hur snabb processorn var.

När processorn sedan användes så stämde det inte, bara den fick jobba lite hårdare så dog den (nästan). Kärnorna var långsamma på att kommunicera och fanns inte minnet i L2 cachen så gick det mycket långsammare.

SIMD:
För att simd instruktioner skall fungera måste minnet ligga i cache. Jag tror det är ett krav och allt måste ligga där. Ligger det inte i cache fungerar inte operationen och då går den ner till att tugga varje instruktion var för sig.
AMDs 9000 model kan köra AVX 512 i full fart. Skrivs koden för detta så är det mycket snabbare än att beta av instruktion för instruktion.

Att läsa in en hel cache-line är inte "prefetching", det är en optimering/implementationsdetalj i moderna CPUer.

Moderna CPUer är rätt bra på att lura ut accesspatterns + att de sedan länge har multi-portade minnes-system, så behöver inte alls påverka prestanda bara för att man accessar data som råkar ligga på olika cache-lines.

Vidare är TLB-L1$ jämfört med L1D$ ofta mer prestandakritisk, hur optimerar du för det??? En (av allt flera) orsaker till varför ARM64 har prestandafördelar mot x64_64 kommer av att 4k page-storlek må ha varit optimalt på 80/90-talet, det är inte längre optimalt (MacOS kör 16 kB page på ARM64, Linux har så smått börjat gå över till 64 kB page på server-kärnor).

Windows är som vanligt ett haveri sett till prestanda, där tragglar man på med 4kB även på ARM64.

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem
Skrivet av Yoshman:

Att läsa in en hel cache-line är inte "prefetching", det är en optimering/implementationsdetalj i moderna CPUer.

Moderna CPUer är rätt bra på att lura ut accesspatterns + att de sedan länge har multi-portade minnes-system, så behöver inte alls påverka prestanda bara för att man accessar data som råkar ligga på olika cache-lines.

Du sa två saker där, att de inte är det och att det är det.

Det andra du skrev stämmer. Att CPUer kan gissa sig till hur data skall hämtas och därför är det bra att lägga minne så processorn har lättare att gissa

Permalänk
Medlem
Skrivet av klk:

Har googlat på en hel del och även "pratat" med olika AI verktyg. Jag vet ju att om jag skulle lämna "luckor" så blir jag sågad vid fotknölarna med en gång

Nej, du möter motstånd för att du kommer med bananas påstående som inte ens en junior utvecklare hade kommit med.

Skrivet av klk:

Vad jag inte förstår är hur man i Rust skulle kunna hantera block med minne och samtidigt få säkerhet utan att gå utanför blockets gränser med smidigare kod än exempelvis C++.

Det låter som att du borde läsa på om Rust istället för att jag ska sitta och återberätta saker som går att Google:a sig fram till.

Snabba svaret är att känna till storleken av det som allokeras och att garantera referensers livslängd och ägandeskap.

Skrivet av klk:

Repeterar att jag självklart vet att det går. Problemet är att språken inte är gjorda för det och det ser genast mycket konstigt ut. I alla fall där jag lyckats hitta något som liknar. Och eftersom det är det enda jag hittat så finns det ingen poäng för C/C++ utvecklare att byta till miljö som är krångligare och inte alls har samma ekosystem.

Nu svamlar du... "språken är inte gjorda för det" vilka språk? Pratar vi fortfarande om Rust?
Andra språk ser konstiga ut eftersom du inte kan dom.

Det jag läser: "Andra språk ser inte ut som C++ så jag ser ingen anledning till att byta".
Gotcha, sure, byt inte då. Ingen som sagt att du ska byta. Folk ber dig bara att sluta ljuga ihop påstående om C++ och andra språk.

Skrivet av klk:

Så svårt är det heller inte att se på kod eller hur någon löser problem för att förstå vad som är möjligt.

Svammel, du sa precis att "Problemet är att språken inte är gjorda för det och det ser genast mycket konstigt ut." så uppenbarligen har du svårigheter med att se på kod.

Skrivet av klk:

Vi har ju diskuterat imperativ kontra deklarativ kod (vet att du och jag tycker olika).

Än en gång så är det inte du och jag som har olika syn på paradigmens innebörd. Du har hittat på någon egen betydelse, lite som att referera till en rät vinkel som 77 grader.

Skrivet av klk:

En websida skall göra. Websidan kommer hantera 10 kommandon (anrop) för att göra det enkelt. Och skall sidan få lov och skicka anropen till servern måste det vara av inloggad användare.

Sidan måste nu ha två state: 1) användare är inte inloggad, 2) användare är inloggad
Än så länge är det inga problem, här är det nästan bara att släcka ner det mesta för icke inloggad användare.

Sidan behöver marknadsföras och det bör vara möjlighet att testa sidan.
Ett till state införs och det är "gäst".
Sidan kan nu ha tre olika state (inte inloggad, gäst, användare).
De 10 olika kommandona blir något rörigare då flera där fungerar olika beroende på sidans state.

Så kommer ett fjärde state, nu är det superuser. 4 olika state på en ganska enkel html sida som nu plötsligt inte är lika enkel längre.

Detta har inget med tidigare referens till paradigm att göra...

Skrivet av klk:

Vad vill jag säga med ovanstående.

Det vet absolut inte jag och troligen inte du i heller

Skrivet av klk:

Om man är van vid att endast göra enkla saker, kanske skriva ihop något för att lösa problem och knappt någon annan kommer titta på det eller att man har en begränsad del i ett system där det mest är underhåll. Då är ovanstående "okänt".

Du svamlar igen och har tydligt inte en aning om vad du pratar om. Om du har en inloggning så kommer du ha en server-sida med API eller annat som hanterar authentication och authorization.

Vad har detta med att skriva ihop saker lätt, få antal användare eller underhåll att göra och varför skulle det vara okänt??

Jag har inte hört sådan smörja på länge ...

Skrivet av klk:

Men om ett större system skall skrivas och de inte exakt vet alla krav mer än på ett ungefär. Då kan en prototyp vara enkel och få fram men små förändringar kan göra att det snabbt blir mycket svårt.

Du svamlar igen... Jag har varit med och utvecklat system som successivt utökats efter lansering utan problem.

Skrivet av klk:

I den här tråden diskuterar vi säkerhetsproblem på grund av minnet. Nästan som att det inte finns något annat.

Nej, vi diskuterar minnessäkerhet så det är inte samma sak.

Säkerhetsproblem pga minne kan uppstå som följd av användning av språk som inte är minnessäkra.

Skrivet av klk:

Klarar inte utvecklare en arkitektur där minnet sköts även om det görs för "hand", så hur skall den utvecklare klara att hantera komplexa situationer med state?

Du har fortfarande inte förklarat vad du menar med state?

Permalänk
Datavetare
Skrivet av klk:

Du sa två saker där, att de inte är det och att det är det.

Det andra du skrev stämmer. Att CPUer kan gissa sig till hur data skall hämtas och därför är det bra att lägga minne så processorn har lättare att gissa

Vad menar du?

Att läsa in en cache-line görs bara därför minst en byte som faller inom cache-line refereras. Endera explicit från programmet eller som en bi-effekt av att prefetchern drar in cache-line.

Det är separat från: cache-lines har en fix storlek och alla bytes som ingår läses/skrivs i en smäll. Detta oavsett orsak till varför den linjen är på väg in eller på väg ut.

Och nämnde också: moderna CPUer är kapabla att läsa/skriva flera cache-lines samtidigt, så är idag mindre kritiskt att hålla access inom samma cache-line.

Prefetchern i alla high-end CPUer är idag kapabel att hålla ordning på flera samtida "stream-access:er". Så att hålla på att packa strängar i relativt små buffertar är optimeringar som borde ha stannat i förra årtusendet (det skrivet, man ska fortfarande inte göra "korkade" saker, t.ex. som att hålla en sträng som en länkad lista av bytes...).

Exempel på vettig optimering än idag: small string optimization, som typ "alla" sträng-implementationer gör idag, oavsett språk.

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem
Skrivet av Yoshman:

Vad menar du?

Tänkte på prefetchers. Förr behövde kunde man behöva lägga in instruktioner för att dra nytta av prefetchers men dagens processorer har (enligt dokumentation) logik för att förstå när de här skall användas.

Exempel:
- Utan prefetchers så om minnet inte sviker mig så laddas två cache lines för en läsning i minnet.
- Med prefetchers kan det läsas en hel del minne till.

Jag känner inte till att processorer är så duktiga att de klarar av att gissa sig till adresser när dessa minnesblock allokeras separat. Möjligen kan man misstolka att det faktiskt är så om det är ett litet testprogram som körs och då laddas hela minnesutrymmet som programmet använder in i cache om det är någon typ av allokering som håller samman data, fråga mig inte hur utan spekulerar bara.
Har strängarna lästs in i cache och man testar om dem och programmet är litet är sannolikheten hög att de redan finns där.

Har gjort en del prestandatester på det här, har bland annat ett objekt som används mycket där värden skickas
[namn][värde][namn][värde][namn][värde][namn][värde]
Kan skickas på fler sätt som [värde][värde][värde][värde] eller andra kombinationer. Och då måste objektet jämföra namnet för att hitta värdet.
Det här objektet är oväntat snabbt och det har troligen att göra med att allt ligger i enda buffer.

Permalänk
Medlem
Skrivet av orp:

Nu svamlar du... "språken är inte gjorda för det" vilka språk? Pratar vi fortfarande om Rust?
Andra språk ser konstiga ut eftersom du inte kan dom.

Ursäkta om jag inte kan svara på dina inlägg, men jag vet att du anser att det enda jag gör är att svamla.

Vad vi än diskuterar i svårighetsgrad för olika språk så tror jag de här minskar i betydelse på grund av AI.

Skall snart (helgen) posta upp objektet som kan lagra flera filer i en fil, får jag lite tid ikväll kanske redan idag. Det här AI är ju helt galet med hur effektiva utvecklare blir. Då tycker jag ändå att C++ är klart sämre när det kommer till att generera kod jämfört med exempelvis javascript eller python (inte testat med andra språk).

Att C++ skulle vara för "svårt" är inte ett argument längre

Permalänk
Datavetare
Skrivet av klk:

Tänkte på prefetchers. Förr behövde kunde man behöva lägga in instruktioner för att dra nytta av prefetchers men dagens processorer har (enligt dokumentation) logik för att förstå när de här skall användas.

Exempel:
- Utan prefetchers så om minnet inte sviker mig så laddas två cache lines för en läsning i minnet.
- Med prefetchers kan det läsas en hel del minne till.

Jag känner inte till att processorer är så duktiga att de klarar av att gissa sig till adresser när dessa minnesblock allokeras separat. Möjligen kan man misstolka att det faktiskt är så om det är ett litet testprogram som körs och då laddas hela minnesutrymmet som programmet använder in i cache om det är någon typ av allokering som håller samman data, fråga mig inte hur utan spekulerar bara.
Har strängarna lästs in i cache och man testar om dem och programmet är litet är sannolikheten hög att de redan finns där.

Har gjort en del prestandatester på det här, har bland annat ett objekt som används mycket där värden skickas
[namn][värde][namn][värde][namn][värde][namn][värde]
Kan skickas på fler sätt som [värde][värde][värde][värde] eller andra kombinationer. Och då måste objektet jämföra namnet för att hitta värdet.
Det här objektet är oväntat snabbt och det har troligen att göra med att allt ligger i enda buffer.

Precis som kompilatorer gått från "de kan behöva en hjälpande hand..." till att rätt mycket vara betydligt bättre än nästan alla programmerare har en liknande utveckling skett på CPU-sidan.

För ett par år sedan rensades majoriteten av alla prefetch hints bort från Linux-kärnan. Orsaken var därför att resultatet blev bättre prestanda på moderna CPUer...

Har bara använt explicita prefetch-instruktioner en enda gång över alla år. Det i ett projekt där målet var att bygga back-bone routers med standard Intel Xeon-servers ihop med väldigt specialdesignad programvara. För att få det bra hade vi hjälp från arkitekter på Intel-sidan som varit med och designat CPU-modellen vi använde.

I.e. om man tror att detta är en bra idé: se till att verkligen testa på "riktiga" fall, för är extremt sannolikt att det bara blir långsammare då man lätt "stör" de optimeringar som finns i CPUn. Och om det råkar fungera på model XYZ001 är det inte alls säkert att det fungerar lika bra på XYZ002...

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem

Angående AI och vad man plötsligt kan göra

sqlite som är världens mest använda databas, nackdelen där är att data måste in i databasen och struktureras.

Något "vi" skulle ha nytta av och kan tänka mig att flera har. Det är en "databas" som kan skanna av utvalda filer som kanske ligger i en mapp i formatet CSV eller liknande och skriva SQL mot dessa för att selektera data mellan dem.
Givetvis går det inte utan att de kan matchas med varandra men något i den stilen

Någon som vet om ifall det finns sådant idag?

Permalänk
Medlem
Skrivet av klk:

Ursäkta om jag inte kan svara på dina inlägg, men jag vet att du anser att det enda jag gör är att svamla.

Det är för att din svar uppfyller en eller flera av följande punkter:
1. Inte är relaterat till tråden.
2. Inte är förankrat i verkligheten.
3. Inte är logiskt sammanhängande.
3. Inte är språkligt korrekt. (Jag menar inte att inlägg behöver vara rättstavade eller grammatiskt korrekta men dina svar är i somliga fall så illa formulerade att jag inte förstår vad du menar.)

Skrivet av klk:

Skall snart (helgen) posta upp objektet som kan lagra flera filer i en fil, får jag lite tid ikväll kanske redan idag. Det här AI är ju helt galet med hur effektiva utvecklare blir. Då tycker jag ändå att C++ är klart sämre när det kommer till att generera kod jämfört med exempelvis javascript eller python (inte testat med andra språk).

Stopp, stopp, stopp. Stanna upp och fråga dig hur detta bidrar till diskussionen om C++ och minnessäkerhet och vad du ens vill säga genom att göra ett sådant exempel. Jag personligen ser inte att det tillför något till diskussionen redan nu, så spar oss båda tid genom att inte göra detta.

Permalänk
Medlem
Skrivet av klk:

Angående AI och vad man plötsligt kan göra

sqlite som är världens mest använda databas, nackdelen där är att data måste in i databasen och struktureras.

Något "vi" skulle ha nytta av och kan tänka mig att flera har. Det är en "databas" som kan skanna av utvalda filer som kanske ligger i en mapp i formatet CSV eller liknande och skriva SQL mot dessa för att selektera data mellan dem.
Givetvis går det inte utan att de kan matchas med varandra men något i den stilen

Någon som vet om ifall det finns sådant idag?

Närmaste jag vet är Language-Integrated Query (LINQ) som jag använder i C#.

Kanske finns portningar av konceptet till C++?

Visa signatur

Ryzen 7 7800X3D | ASUS TUF Gaming B650-Plus WIFI | Kingston 32GB (2x16GB) DDR5 6GT/s CL30 FURY Beast | Kingston Fury Renegade M.2 NVMe SSD Gen 4 2TB | MSI RTX 4060 8GB | Fractal Design Define S | MSI MPG A850G 850W | Thermalright Phantom Spirit 120 SE | Windows 11 Pro | AOC 27" AGON AG276QZD2 OLED QHD 240 Hz

Permalänk
Skrivet av klk:

prefetchers fungerar så mycket bättre om minnet hänger samman. När processorn läser minne så chansar processorn och läser extra mycket. Låt säga att processorn läser från adress 100, det är bara ett värde från adressen som läses in och det är kanske 4 byte. Men processorn läser inte bara dessa 4 byte utan den läser minst 64 byte (x86,ARM). Minst en cache line som är 64 byte. Vet man det så vet utvecklaren att det ligger mer minne i L1 cache och den är blixtsnabb.
Kan man hålla samman information till olika block så här så kan man få träff i L1 hela tiden då processor förladdar minne.

Jo, jag vet hur både cache och prefetching fungerar. Det är därför jag önskar att du håller dig till etablerad terminologi istället för anekdotisk bevisföring.

Next-line prefetching har funnits länge, men att naivt hämta nästa cache-line tär på bandbredden mellan L1 och L2. Det fungerade bra i single core, men när det nu kommit CPUer med fler kärnor som delar på samma L2-cache har det visats sig att det kanske inte var en toppenidé att spekulativt hämta nästa cache-line. Det är viktigare att hämta data vi vet kommer användas av andra kärnor än att hämta ett block som kanske kommer användas. Moderna CPUer har mer adaptiva modeller för när prefetching görs. För L1I är next-line prefetching nästan alltid en vinst, men för L1D behövs det typiskt mer än någon enstaka access för att nästa cache-line skall hämtas. Om vi återigen pratar om AVX512 krävs det långa strängar för att det skall ske.

Skrivet av klk:

Gör du tvärtom så att det är 10 olika adresser. Måste man vandra igenom varje sträng behöver processorn gå till ny adress och det kan i värsta fall innebära att den behöver gå till ram. Samtidigt som den går till ram kan den behöva kasta bort minne som är laddat i L1 cachen (den är inte så stor).

Om du istället för att allokera ett 10-strängsblock allokerar 10 separata minnesblock där texten kommer ligga, är det mer sannolikt att de kommer ligga i en klump, allokerade back-to-back, eller utspridda i minnet på 10 random adresser utan någon form av lokalitet?

Skrivet av klk:

Skillnaden på de här två sätten att hantera minne blir ofta större än vad man tror, speciellt som desto mer processorn jobbar desto större skillnader. Orsaken är att när processorn jobbar hårt jobbar den ofta med mycket minne och då måste mer kastas bort och laddas om.

What? Du kommer ha vadå? En storlek och en next-pekare (16 bytes) för 9 extra data block, om de lagras i anslutning till det allokerade blocket, och 9 extra strängobjekt, data-pekare och storlek (16 bytes), på stacken/i register. Det är 288 bytes extra. Det kommer inte att svämma över några cachar

Skrivet av klk:

SIMD:
För att simd instruktioner skall fungera måste minnet ligga i cache. Jag tror det är ett krav och allt måste ligga där. Ligger det inte i cache fungerar inte operationen och då går den ner till att tugga varje instruktion var för sig.
AMDs 9000 model kan köra AVX 512 i full fart. Skrivs koden för detta så är det mycket snabbare än att beta av instruktion för instruktion.

Detta är ett blockschema för Lion Cove. Längst till vänster är Vector/FP-enheten. Den är pipeline:ad och kan starta evalueringen av upp till 4 SIMD-operationer per cykel. Precis som andra komplexa X86-instruktioner splittras i microoperations (uops) kommer en SIMD-instruktion har en source-operand i minnet splittras i en load-uop och en compute-uop i front-end. När alla ingående värden i adressuttrycket är tillgängliga kan load-uopen scheduleras och data hämtas från L0. Är det en miss kommer den hämta data från nästa nivå av cache osv. Först när minnesoperanden är inläst i Vector Register File kan compute-uopen scheduleras.

Du har ju rätt i att om inte alla operander är tillgängliga så kan inte instruktionen exekveras, men L0 har en bandbredd på 3x256b eller 2x512b per cykel så man övergår inte nödvändigtvis till att tugga varje instruktion för sig. Ha samtidigt i åtanke att uttrycket "tugga varje instruktion för sig" är helt missvisande för en modern superskalär CPU där den spekulativ exekveringen kan ligga flera hundra instruktioner "före" programräknaren så en cache-miss här kanske inte är hela världen.

Om du nu inte har koll på hur saker och ting funkar, hur kan du vara så säker på att du skriver ditt program på ett sätt som gör att det blir "mycket snabbare"?

Du har rätt i sak att det sannolikt kommer att gå fortare med din modell, men jag är skeptisk till att det kommer gå "mycket" snabbare och kanske inte av de anledningar du tror.

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

Det fungerade bra i single core, men när det nu kommit CPUer med fler kärnor som delar på samma L2-cache har det visats sig att det kanske inte var en toppenidé att spekulativt hämta nästa cache-line.

Innan jag svarar så undrar jag om du är rätt uppdaterad om L2-cache? Mig veterligen så är dessa separata för varje kärna.

Permalänk
Skrivet av klk:

Innan jag svarar så undrar jag om du är rätt uppdaterad om L2-cache? Mig veterligen så är dessa separata för varje kärna.

Ett kluster om 4 E-cores delar L2, vet jag, och ChatGPT hävdade att det gjorde även Cortex-A* och Apples M*-modeller, dock vet jag inte exakt hur dessa är konfigurerade. Det kommer även komma i framtida arkitekturer från åtminstone en stor tillverkare.

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

E-cores delar L2, vet jag, och ChatGPT hävdade att det gjorde även Cortex-A* och Apples M*-modeller.

Ja det där j***a E-cores kanske gör det men inte på normala kärnor (inte kollat).

E-cores är en extremt korkad lösning från Intel när det skrivs kod som behöver prestanda, begriper inte hur de tänkte. Kod måste anpassas så de inte lägger jobb på de här för då är det sirap i datorn.

Permalänk
Medlem
Skrivet av klk:

Innan jag svarar så undrar jag om du är rätt uppdaterad om L2-cache? Mig veterligen så är dessa separata för varje kärna.

Det varierar mellan olika CPU modeller. Liksom det mesta annat.

En del har separat L2 cache per kärna, en del har en L2 cache som delas mellan alla kärnor.
Och man kan naturligtvis ha varianter däremellan - t.ex. att kärna 0 och 1 delar på en L2-cache, medan kärna 2 och 3 delar på en annan L2-cache (antaget en 4-kärnig processor)

L2 cache som delas mellan alla kärnor var vanligare i tidiga multi-core processorer, medan separata L2 cachar är mer vanliga i nyare processorer.

Permalänk
Datavetare
Skrivet av klk:

Ja det där j***a E-cores kanske gör det men inte på normala kärnor (inte kollat).

E-cores är en extremt korkad lösning från Intel när det skrivs kod som behöver prestanda, begriper inte hur de tänkte. Kod måste anpassas så de inte lägger jobb på de här för då är det sirap i datorn.

Världens just nu snabbare CPU-kärna, Apple M4, har ju delad L2$ mellan upp till 4 P-kärnor och den är vad jag vet alltid delad för E-kärnorna (som kan vara 2, 4 eller 6 st beroende på modell).

Intels, Apple och numera även Arms "E-kärnor" (i senaste generationen används Cortex A7xx istället för Cortex A5xx som E-kärnor) är inte längre "långsamma kärnor som inte duger till något". De presterar i praktiken på en nivå vi hade på de absolut snabbaste CPU-modellerna för ett par generationer sedan.

Här får man vara med på att trenderna och "best-practice" ändras med tiden.

Länge ansågs små och väldigt snabb L2$ vara "optimalt", något Intel introducerade med Nehalem.
Just nu går trenden mot väsentligt större L2$, det med lite högre latens. Apple sticker ut lite med att ha P-kärnor med delad L2$, fast som "plåster på såren" har man då 16 MB L2$ att tillgå...

Hur optimerar man för det?
Det gör man inte om man inte är ute efter att designa något som är överspelat om ett par år...

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem
Skrivet av Yoshman:

Världens just nu snabbare CPU-kärna, Apple M4, har ju delad L2$ mellan upp till 4 P-kärnor och den är vad jag vet alltid delad för E-kärnorna (som kan vara 2, 4 eller 6 st beroende på modell).

"snabbaste" beror helt på vad du mäter. ARM är inte gjord för att vara snabb, den är gjord för att vara energieffektiv. ARM har inte jobbat på att få samma simd prestanda som x86 gjort.

Apple är också de som ligger bakom LLVM för att kunna kompilera upp kod till deras platform och jag kan tänka mig att de anpassat så den kompilatorn är duktig på att optimera för deras processor.

Apple som har så slutet system kan också leka mer för att få till siffrorna.

När vi väljer CPU i molnet så är det uteslutande x86, beräkningsintesiva och/eller att mycket data processas är snabbast där.

Hade varit intressant och jämföra kod kompilerad med GCC eller LLVM för apple, det skall gå men apple tror jag inte supportar GCC. I alla fall så de som sitter med apple datorer har i princip uteslutande LLVM för att kompilera