Python's Unflattering Performance Review
Why is this Languages meme funny?
Level 1: The Tortoise and the Hare
Imagine a race between two characters: a friendly tortoise and a speedy hare. In our story, Python is like the tortoise and C is like the hare. Python (the tortoise) is very friendly and easy to work with – it takes its time, moves steadily, and makes sure every step is nice and clear. C (the hare) is super fast and powerful, zooming ahead at top speed, but to be that fast it’s a bit more wild and not as easy to handle if you’re not trained. Now, in the classic fable The Tortoise and the Hare, the tortoise wins in the end through patience and consistency. But in the programming world, when it comes to pure speed, the hare (C) usually wins the race every time if both are running under the same conditions. 🐢🏁🐇
This meme is funny because it’s like we’re watching Python brag about its good qualities – it’s saying “I’m known for being easy to understand, and I’m great for big data and science tasks!” with a big proud smile. These are true; Python is like that helpful friend who explains things in a simple way and has all the tools you need ready to go. Then, the other character (like the boss in the scene, or think of it as the hare poking fun) says, “...and you’re also known for being slower than C.” It’s as if the hare leans over and teases, “you may be nice, but you sure take your sweet time!” At this point, Python’s smile fades and it looks a bit embarrassed or upset, just like anyone would if their weakness was pointed out after their strengths.
In very simple terms, the meme is telling a joke about not being able to have everything perfect. Python the friendly tortoise can’t also be the fastest runner — those two things (being super easy and super fast) are kind of opposites in many cases. It’s like if you have a very easy, step-by-step way of doing something, it might not get done as quickly as a more direct but complicated way. People find it funny because they imagine Python as a person hearing compliments and then a gentle criticism, and Python making that “ouch, you got me there” face. If you’ve ever been really good at something but had a little flaw that your friends tease you about, you know the feeling! For programmers, we kind of treat our favorite languages like buddies, and Python is that buddy who everyone likes but we chuckle about how it’s not the speediest. The meme captures that feeling in a simple, relatable way: you can be lovable and capable (Python), yet still have that one thing (speed) that you’re just not the best at, and that’s okay. That contrast is the whole joke – and why it makes developers grin and think, “So true, poor Python!”
Level 2: Readable but Not Rapid
Let’s break down the joke in simpler terms. Python is a programming language known for being very readable and easy to use. When people say Python is "easy to understand," they mean the code syntax is designed to be clean and kind of intuitive. For example, in Python if you want to print a message, you just do:
print("Hello, World!")
In C, doing the same thing takes a bit more work and looks more complex:
#include <stdio.h> // include a library for input/output
int main() {
printf("Hello, World!\n"); // print the message
return 0; // end the program
}
The Python version is one straightforward line, essentially telling the computer “print this message.” It reads almost like English. The C version has a lot more ceremony around it – you have to include a library, define a main function, use a specific function printf, and end the program explicitly. This little example shows why Python is celebrated for being easy to understand and write. You spend less time on setup and syntax and more time on the actual problem you're solving. Python enforces indentation to structure code instead of lots of { } braces or keywords, which many find makes the code visually cleaner. All these language quirks (like using whitespace and having high-level constructs built-in) make Python code often look quite straightforward, even to a relatively new programmer.
Now, Python is not just popular for toy examples — it shines in real-world fields like data science and scientific computing. When the meme says Python is known for its "libraries in data science," think of libraries as pre-built packages or toolkits. Python has an extensive collection of these packages that are widely used in data analysis, machine learning, and artificial intelligence. For instance:
- Pandas: A library that makes it easy to load, manipulate, and analyze data tables (like Excel sheets or SQL tables) in just a few lines.
- NumPy: Provides powerful tools for working with arrays and matrices of numbers – essential for math, stats, and science tasks.
- Matplotlib and Seaborn: For creating graphs and charts from data.
- SciKit-Learn: For machine learning algorithms (like training models to make predictions).
- TensorFlow and PyTorch: For building and training neural networks (used in deep learning).
Because of these libraries, someone working with data can do a lot of complex stuff quickly in Python. Say you want to analyze a million-row dataset and plot some trends; with Python’s libraries, you can accomplish that with just a few commands, whereas doing it from scratch in a language like C would be a huge project (you’d have to handle file I/O, math, plotting logic, etc., mostly on your own or with less integrated libraries). That’s why Python is often joked about as the “Swiss Army knife” of data science – not necessarily because it’s the fastest at doing calculations, but because it gives you all the tools in an easy-to-use way. It’s very productive for the person writing the code.
However, this convenience and ease come with a well-known downside: Python is generally slower in execution speed compared to a language like C. When the meme says Python is known for "being slower than C," it refers to the fact that programs written in Python typically run with more delay or use more CPU time to do the same task than if that program were written in C. If you had a race, Python would be the slower contestant and C the faster one.
Why is Python slower? One big reason is how they run programs. C is a compiled language. "Compiled" means you write your code, then a special tool (a compiler) translates that human-readable C code into machine code (the very detailed instructions that the computer’s hardware understands). Once compiled, the program runs directly on the machine. Python is an interpreted language. "Interpreted" means you don’t compile the code down to raw machine instructions ahead of time. Instead, another program (the Python interpreter) reads your Python code and executes it on the fly, line by line, figuring out what each instruction means as it goes. This interpretation process acts like an extra layer: it makes coding easier (because you can run code immediately and it’s very flexible), but it also means each operation has a bit more work to do. It’s like the difference between reading a book in your native language (C’s way) versus reading a book with the help of a translator translating every sentence live (Python’s way). The translated one is going to take longer to get through, right?
Another reason is Python’s dynamic typing. In Python, you don’t have to declare the type of each variable; the language figures it out at runtime. For example, you can just do x = 5 without specifying if x is an integer, a float, etc., and later even do x = "hello" assigning a string to the same variable. That’s very convenient, but behind the scenes, Python has to keep extra information about what type x is, and every time you use x in an operation, it has to check that info. In C, if you declare int x = 5;, the compiler knows x is an integer and it stays an integer (no changing types). So operations on x in C are straightforward and directly use the fact that it’s an integer. In Python, this flexibility adds overhead — it’s like each time Python does something, it carries a backpack of context (type info, safety checks) that slows it down a bit, whereas C travels light but you had to pack carefully upfront.
In practice, this means if you write a program to do something heavy, like crunch through millions of calculations or process a huge file, a pure Python version might run significantly slower than a C version of the same algorithm. We’re talking differences that can be 10 times slower, 50 times slower, sometimes even more, depending on the task. For example, a loop doing a simple arithmetic operation a million times could be done in a blink in C, but might take noticeable time in Python. That’s why Python developers often rely on those optimized libraries: those libraries internally use C/C++ or optimized code for the heavy parts, so you get the ease of Python without paying the full performance price. It’s a bit ironic — Python is slower, but it stays super useful by quietly borrowing speed from C in exactly the scenarios where raw speed really matters (like heavy math).
So the meme is funny to developers because it lists Python’s great qualities – readability (easy for humans to read) and usefulness in data science (tons of tools ready to go) – and then adds, “but hey, isn’t it also known for being slow?” It’s pointing out a kind of well-known irony or language quirk: you get all these nice things with Python, and in exchange, you accept that it won’t win a race against a lower-level language like C. Pretty much every programming language has something it’s good at and some trade-off or downside. In Python’s case: human-friendly, yes; lightning-fast execution, not so much.
For a junior developer or someone just learning, this meme also conveys a gentle lesson: When picking a language or a tool, remember there’s no free lunch. If something is super beginner-friendly and powerful (like Python is for writing code and doing complex tasks easily), it might have hidden costs such as performance. Conversely, languages known for being extremely fast and powerful (like C, or C++ or Rust) often have a steep learning curve or require you to manage a lot more details manually. It’s why Python and C often get compared – they kind of sit at opposite ends of the spectrum in many ways.
The context of the meme using The Office setup emphasizes the humor: imagine Python as a proud employee listing their strengths in a performance review – “I write very clear code, I’ve become the star of data science projects” – and then the boss reminds them of the area they got a low score in: “speed (performance)”. Python’s face falls, because, well, it’s true and there’s no denying it. 😅 Developers find this funny because we personify programming languages like this all the time, almost like they have personalities. Python’s personality in this meme is the super helpful, nice co-worker who unfortunately is a bit slow getting the work done. C’s personality by contrast might be the efficient, no-nonsense worker who isn’t very approachable. Depending on the situation, you might prefer one or the other – and often in big projects, you actually use them together to balance things out.
In day-to-day terms, if you’re a newcomer: don’t worry that “Python is slower than C” means Python is bad. Not at all! It’s just a different tool. Think of it like a comfy family car vs a race car. A family sedan (Python) is comfortable, easy to drive, and has great features (like a good stereo, AC, lots of cupholders for your data science “beverages” 🍹), but it’s not the fastest car on the track. A Formula 1 race car (C) is extremely fast and powerful, but hard to drive and not very comfortable for everyday use. In coding, you pick the vehicle that makes sense: if you’re doing something where turning around code quickly and having simplicity matters (like trying out a data analysis or automating a small task), Python’s your friendly sedan. If you’re doing something where every millisecond counts (like a high-performance game engine or a program that runs on a tiny device with limited hardware), you might need the race car performance of C, and you’ll accept that it’s harder to handle. And sometimes, you use Python as the “driver” that directs some race car engines under the hood – which is exactly what those Python libraries do with C code. This meme basically gets a laugh by reminding us of Python’s “family car” nature in a cheeky way.
Level 3: The Price of Productivity
From a senior developer’s perspective, this meme highlights the classic performance trade-off we deal with when choosing a programming language. Python is often praised for its developer productivity and readability – writing Python tends to feel like writing in pseudocode or plain English. There's minimal ceremony: no worrying about types for every variable declaration, no intricate memory management, and a very clean, whitespace-significant syntax that many find easy to understand. This is why Python is frequently recommended as a first language to learn and why it has a reputation for being beginner-friendly. A seasoned engineer sees that caption "easy to understand" and nods: indeed, Python’s syntax (using indentation instead of curly braces, high-level constructs like list comprehensions, and a huge standard library of conveniences) lowers the barrier to entry for new developers and speeds up development for experienced ones. Many of us have experienced the joy of converting what would have been 50 lines of C or Java into 5 lines of Python that read almost like plain English. This is Python’s superpower: it optimizes developer time.
The second thing "Python" proudly points out in the meme is its powerhouse status in data science (captioned “libraries in data science” or "usefulness in data science"). Over the past decade or so, Python has become the go-to language for data analysis, machine learning, and scientific computing. This is largely thanks to an ecosystem of libraries (like NumPy, pandas, SciPy, scikit-learn, Matplotlib, TensorFlow, and PyTorch, to name a few) that let you do everything from crunch enormous datasets to train neural networks – often with just a few lines of high-level Python code. A seasoned dev knows that one reason Python won out in data science is not because it’s the absolute fastest at runtime, but because it’s fast to develop with, and you can lean on those libraries (many of which, as mentioned, are written in faster low-level languages internally) to handle the heavy lifting. The meme is spot-on with this contrast: Python is known for scientific and analytic computing today in a way that, say, C isn’t, despite C’s speed. Why? Because in practice, data scientists value being able to prototype and iterate quickly in Python, using those well-tested libraries, more than they value hand-optimizing every last bit of performance themselves. In industry, you’ll often hear a maxim like, “Hardware is cheap, but developer time is expensive.” Python embodies that ethos — it might use more CPU seconds, but it can save human hours, and that trade-off is usually worth it for many applications.
Now, the final punchline of the meme: “being slower than C.” Here the “manager” in the meme (Michael Scott from The Office, using the you_are_known_for format) delivers the well-known downside of Python right after the two big praises. This format is a setup for contrast: it’s funny because it’s true and a little bit embarrassing for Python. No matter how beloved Python is for its elegance and its data science dominance, every experienced developer knows that performance is Python’s Achilles’ heel. When it comes to raw execution speed, especially on CPU-bound tasks (like heavy computations, tight loops, or system-level tasks), Python just can’t keep up with a low-level language like C. The meme captures Python’s resigned face — that look of “yeah, I’ve heard this one before.” 🙃 It’s a shared joke among programmers: we adore Python for making our lives easier, but someone will always point out, often half-jokingly, “Ugh, Python is so slow compared to C!”
In real development scenarios, this trade-off leads to a lot of familiar patterns. Senior devs have seen projects initially built quickly in Python (because it was easy to get started) later hit performance bottlenecks. There’s almost a rite-of-passage story: a small script written in Python grows and becomes mission-critical, then one day it’s too slow for some task, and the team has to consider optimizing. That might mean refactoring the Python code, applying algorithms to do less work, or in some cases rewriting a hot module in C/C++ for speed. This is so common that it’s become an accepted approach: prototype in Python, optimize the critical parts in a faster language if needed. We jokingly call it the two-language solution – Python for productivity, C (or C++/Rust) for performance-sensitive innards. A seasoned engineer reading “slower than C” might recall the countless times they’ve had to explain to product managers why scaling a Python service might require more servers than a C++ service, or why that data processing job takes hours in pure Python but could run in minutes with a C extension (or simply by using vectorized NumPy calls). The humor in the meme is that it encapsulates this whole saga in one facial expression from The Office – Python enthusiastically touting its strengths, then being unable to dodge its well-known weakness.
We also recognize in this meme an affectionate ribbing of Python. In the developer community, poking fun at languages is part of the culture (you’ll see LanguageComparison jokes all the time). Python’s case is interesting because it’s almost universally liked for what it offers, even by people who criticize its speed. So the meme isn’t hating on Python; it’s more like that gentle joke you make about a friend’s little flaw. We laugh because we’ve all been there: maybe you wrote a quick script in Python that worked beautifully, but when you tried to use it on a huge dataset or under heavy load, you went “oh… this is kind of slow.” It’s relatable humor. And importantly, the meme resonates because if you’ve been in development long enough, you’ve learned that you can’t have everything in one language. Python chooses simplicity and power in expressiveness, C chooses control and speed. Each has its language quirks and domains where it shines. As a senior dev, you appreciate that trade-off: you use Python when you want to get results quickly and your bottleneck isn’t a tight inner loop (or you can push that loop to C via a library), and you use C (or similar system languages) when you absolutely need that raw performance or fine-grained control over memory and processor instructions.
The scene used in the meme (from The Office) adds another layer for those familiar: Michael Scott lists positive qualities of an employee (making them smile) and then throws in a negative one, which wipes the smile away. It’s a popular format for memes (“You are known for… good thing, ... another good thing, ... bad thing”). For developers, Python’s “bad thing” is practically a running gag. We’ve all seen benchmarks or heard colleagues jibe, “Sure, Python is great, but it’s not winning any speed contests.” The meme succinctly delivers that jibe. And the reason it’s funny and not offensive is because Python’s slowness is a well-acknowledged reality — even the most die-hard Pythonistas will shrug and go “yeah, fair point, it’s not as fast as C.” In fact, Python’s creator, Guido van Rossum, and the core development team have historically been quite open that Python prioritizes clear syntax and ease of use over raw speed. There’s a famous quote, “Python is fast enough for most things.” The community often cares more about whether the language is fast to write in (developer efficiency) and fast when using the right tools (like those optimized libraries) than about beating C in a micro-benchmark. So the meme lands as a light-hearted truth: Python wears its crown of popularity with pride, but that crown comes with an asterisk about performance. Seasoned devs have a fond chuckle because it captures the exact moment Python’s pride gets a reality check – a dynamic many of us have experienced firsthand in tech discussions and developer humor sessions.
In summary, the senior perspective here is recognizing the trade-offs in language design. Python’s strength is making coding easier and faster for humans, which has led to huge successes (like the explosion of data science and quick scripting). The cost of that choice is that the computer has to work harder (making Python code run slower at the machine level compared to lean, compiled C code). The meme humorously reminds us of this well-known cost. It’s “funny because it’s true,” and because it’s a shared piece of industry wisdom that no amount of Python love or hype can fully escape. Even in 2021 (when this meme was posted), after years of improvements and even projects trying to make Python faster, the core reality remains: Python trades speed of execution for speed of development, whereas C often does the opposite. And as developers, we’ve learned to choose between them (or combine them) wisely depending on what matters for the task at hand. The meme just packages that whole encyclopedic insight into a punchy visual joke.
Level 4: Beneath the Bytecode
At the lowest level, the contrast between Python and C comes down to how the computer actually runs their code. Python executes programs using an interpreter and bytecode, whereas C is executed as direct machine code after compilation. In Python's case (specifically the common CPython implementation), your .py source is first compiled into an intermediate bytecode (those .pyc files). That bytecode isn't the native language of the CPU — instead, a virtual machine (essentially a loop written in C) reads and performs each instruction. This indirection introduces overhead at runtime: every Python operation (even a simple x + y) must go through additional steps like type checking and dispatching to the appropriate C code under the hood. In contrast, C code is compiled all the way down to the CPU's own instructions ahead of time. When you run a C program, the processor is executing exactly the low-level operations you wrote (optimized by the compiler), with no middleman.
For example, consider adding up numbers in a list. In Python, each loop iteration and addition involves multiple layers of work (interpreting bytecode, managing Python objects, etc.), whereas in C it becomes a tight sequence of machine-level instructions:
# Python code (interpreted, dynamic):
total = 0
for x in numbers:
total += x # Each step involves interpreter overhead and dynamic type handling
// C code (compiled, static types):
int total = 0;
for (int i = 0; i < N; ++i) {
total += numbers[i]; // Compiled into a few CPU instructions working directly with memory
}
In the C version, the compiled machine code might use a CPU register for total and loop with minimal instructions (add operations, pointer increments, a compare/jump for the loop). The Python version, by contrast, will internally call out to C functions (to perform the addition on Python objects) every iteration, manage reference counts for memory, and check types at runtime. This is why pure Python tends to be orders of magnitude slower for heavy computational loops. The computer has to do a lot more bookkeeping to execute the same abstract logic.
There are also deeper architectural reasons behind Python's speed limitations. Python uses high-level abstractions (like objects for everything, even simple integers) and a lot of indirection. Each integer 42 in Python isn’t just a raw 32-bit value like in C – it’s an object on the heap with metadata (type information, reference count, etc.). So adding two numbers in Python involves pointer dereferences and function calls (to handle arbitrarily large integers and various types), whereas in C it’s a single CPU ADD instruction on two registers. The cost of abstraction shows up in CPU caching and branch prediction too: C’s tight loops take advantage of contiguous memory and predictable instruction flow, keeping the processor’s pipeline and caches fed efficiently. Python’s interpreter, by contrast, is jumping around a general-purpose evaluation loop, which can be less friendly to the instruction pipeline and cause more cache misses due to its data being scattered (e.g., pointers to objects all over memory).
Another advanced factor is Python’s approach to multi-threading with the Global Interpreter Lock (GIL) in CPython. The GIL ensures only one thread executes Python bytecode at a time per process, which means even on a multi-core machine, Python won’t effortlessly speed up CPU-bound code by using threads. In C (or C++), you can spawn threads that truly run in parallel on different cores (provided you handle synchronization yourself). In Python, threads are useful for I/O-bound concurrency, but they don’t achieve parallel computation for CPU-bound tasks due to the GIL. This is another reason people say Python is “slow” for certain use cases – throwing more hardware at a Python program (more CPU cores) doesn’t help as much as it would in a C program, unless you use multi-processing or native extensions.
It’s worth noting that Python’s performance issues are well-understood, and the language has evolved strategies to mitigate them without sacrificing ease of use. Many of Python’s vaunted data science libraries (like NumPy, pandas, or TensorFlow) are actually written in C, C++, or even Fortran under the hood. Python acts as a friendly glue, an easy-to-use interface that orchestrates high-performance code behind the scenes. So when you do heavy number crunching in Python with NumPy, what’s happening is that you’re calling into highly optimized C/C++ routines (for example, vectorized operations that use SIMD instructions and efficient memory access). This way, Python can have its cake and eat it too: you write in a readable high-level syntax, but you’re leveraging the speed of low-level languages where it counts. The flip side is if you try to implement those heavy computations purely in Python (without native extensions), you’ll quickly run into that slowness the meme pokes fun at. There’s a well-known mantra among performance-minded Python developers: “If your Python is too slow, just do it in C (or let someone else’s library do it in C) under the hood.”
In academic terms, this is a classic example of the abstraction-performance trade-off. Python is a high-level language with lots of abstraction: automatic memory management (garbage collection via reference counting), dynamic typing, and a virtual machine layer. C is a low-level language (closer to the metal) where you manually manage memory (malloc/free), use static types, and compile straight to optimized machine code. Python sacrifices some raw performance to provide a high developer experience – quick coding, easy syntax, and an extensive runtime that handles details for you. C sacrifices ease (manual memory management, verbose syntax, higher chance of crashing on a bad pointer) to squeeze out maximum performance from the hardware. These design decisions are why the meme’s punchline (“being slower than C”) is fundamentally true: it’s practically baked into the physics and math of how the two languages work. Barring special techniques like JIT compilation (which some alternative Python implementations and other languages use to narrow the gap), an interpreted dynamic language will almost always run slower on the CPU than an optimized static compiled language for the equivalent task. It’s not just an unfortunate quirk – it’s the inevitable outcome of Python’s very philosophy of being high-level and flexible. And that is exactly why seasoned developers smirk at this meme: it humorously distills a well-known engineering trade-off into a simple Office scene.
Description
A six-panel meme using the 'You are known for...' format from the TV show 'The Office.' In the left panels, Michael Scott is conducting an interview. In the right panels, Pam Beesly is labeled 'Python.' In the first row, Michael begins, 'You are known for...' and Pam (as Python) excitedly answers, 'easy to understand'. Michael looks unconvinced. In the second row, Pam tries again with a confident smile, 'usefulness in data science'. In the final row, Michael delivers the punchline with a critical expression: 'being slower than c'. Pam's face shifts to one of utter disappointment. The meme humorously highlights the core trade-off of Python: its high-level syntax and powerful libraries make it excellent for developer productivity and data science, but as an interpreted language, its raw performance is a well-known weak spot compared to compiled languages like C
Comments
228Comment deleted
Python: spend 10 minutes writing a script that takes 10 hours to run. C: spend 10 hours writing a script that takes 10 minutes to run
Python is so readable even the quants ship it to prod - right up until the latency SLA hits, then it magically morphs into 10k lines of hand-rolled C extensions nobody claims ownership of
Python developers explaining to management why their data pipeline takes 3 hours: 'But think of all the time we saved not writing semicolons and managing memory!'
Python developers will spend three days optimizing their data pipeline with Cython and multiprocessing, only to realize the real bottleneck was a single unindexed database query. But hey, at least the code is readable enough that the next person can figure that out in five minutes instead of five hours - which is more than you can say for that 'performance-optimized' C codebase from 2003 that nobody dares touch because the original author documented it exclusively in Hungarian notation and regret
Python’s performance strategy is simple: push the hot path into NumPy/Cython, then benchmark the 90% glue while debating the GIL
Python: 10x easier to write, 10x slower to run - until the SLOs force that C interop hotpath rewrite
Python: easy to read, dominant in data science, and blazingly fast - right after you hand the hot loop to NumPy’s C while the GIL holds your coffee
hmm Comment deleted
what a coincidence Comment deleted
memalloc Comment deleted
oh yea because everyone here steals stale memes from reddit, deal with it Comment deleted
idk I'm not finding it on reddit, must've cone from a different platform Comment deleted
well the other platform stole from reddit cuz it's a highly upvoted post on r/programminghumor Comment deleted
is it? I can't find it Comment deleted
probably already taken down by the jannies, anyway I saw it yesterday Comment deleted
nope, found it https://www.reddit.com/r/ProgrammerHumor/comments/p2fgpb/you_evil_people/ Comment deleted
damn, respect Comment deleted
I looked both in hot and top last week, but couldn't find it Comment deleted
Lol C is not even slow compared to other object oriented languages Comment deleted
not at all, no Comment deleted
Yeah its only slow if you compare it to asm but asm cant be compared to object oriented language Comment deleted
rust is also slightly faster technically but really how fast your code runs comes down to how well you write it Comment deleted
Well the overhead is the major thing that can be compared between stuff Comment deleted
aye, Rust has 0 cost abstractions fyi 🙃 Comment deleted
That sounds pretty good Comment deleted
C is not slow even compared to asm.. it all depends on how you write your code and how you compile it. If you build the project with the instrumented profiling stage first, I doubt you’d be able to write it faster in asm, provided you have the same skills in both languages. And if you target multiple CPU models (not even talking about different brands of the same arch, like Intel & AMD on amd64) I bet you won’t be able to outperform a well built C with asm, at least if the project is not a basic algo and you don’t have an infinite time to code it Comment deleted
C still has overhead, compared to asm it's always slower Comment deleted
> It’s always slower No, it isn’t.. I was working in a HPC (high-performance computing) environment for 10 years, coding in C and asm by hand. You should know your CPU so so well to be able to code something in asm faster than a well-built C, that it’s almost impossible Comment deleted
I mean perfect asm will always be better than perfect C obviously abstractions help massively with programming effectively Comment deleted
Just make sure not to run this: {} - [] Comment deleted
not sure what that does Comment deleted
Because the opertor - automatically casts everything to numbers, and an empty array is false when converted to booleans and any object is a true if converted to booleans it will completely logically subtract 1 - 0 what then equals perfectly logically: -0 Comment deleted
so {}-[] is the same as -0, yes? Comment deleted
Yes Comment deleted
why negative zero? Comment deleted
Best of all is I can clearly remember that in school we were taught that 0 has no sign at all Comment deleted
same until we got to Mengenlehre (group theory I think?) where it's not in N+, but in N+0 (positive Natural numbers, positive Natural numbers and 0) Comment deleted
Lol Comment deleted
Ask the IEEE 754 standard Comment deleted
but that's only for floats, no? Comment deleted
nvm it's js I remember Comment deleted
Yeah🤡 Comment deleted
glad I can use rust/wasm now, so I can decide between using a string, a string pointer or a string object which all have wildly different use cases Comment deleted
Well C++ you can choose that too PLUS you can do it in w_char (unicode) or as normal ascii Comment deleted
No.. Comment deleted
mate C literally compiles to asm, it can't be faster than that Comment deleted
I guess you don’t get the point.. the fact that C compiles to the same binary code that asm doesn’t make it slower.. to write proper asm code you should understand so much of the underlying CPU functioning, that today you can’t outsmart the compilers.. Comment deleted
I already told you, I'm not talking about practical performance. Ofc abstractions make it easier for the programmer to write good programs because there's a shitton of optimizations that can be applied to code that's often used, but are complicated as hell. Comment deleted
Then what are you talking about? 🤔 Comment deleted
reading comprehension. I already told you at least twice Comment deleted
You mean a theoretical abstract performance completely detached from the real world specifics? Like infinite knowledge and infinite coding time? Comment deleted
Is this sarcasm I dont get it exactly Comment deleted
This would be funnier if it would say "being slower that JavaScript" but idk if this would actually be true Comment deleted
comes down to the task - technically, pure js is faster because it's been optimized to death, but python has heaps of built-in compiled libraries Comment deleted
Lol js is JIT compiled thats a huge overhead lol Comment deleted
And the best thing is that Rust can outperform C the same way C can outperform asm Comment deleted
rust has less overhead than C, which makes it faster Comment deleted
Rust has C as the backend.. what do you mean? 🤔 Comment deleted
no it doesn't lol Comment deleted
it compiles to asm just like any other compiled lang Comment deleted
afaik it compiles to llvm and then to asm Comment deleted
asm is the end product, anyway, I don't know much about the intermediate process Comment deleted
Asm is not the end product.. Comment deleted
asm as in the byte code, not the readable code Comment deleted
But asm has numerous stages to be “converted” to bytecode Comment deleted
it's a direct analogue to what's in the bytecode Comment deleted
Yepp Comment deleted
And it’s not the matter of overhead in instructions.. if you have a L2 cache miss, it’s like 100 times (or even more) slower.. Comment deleted
The nowadays compilers have much more information about what code does than the coder, except some simple algo. Have you tried instrumented profiling? Comment deleted
> perfect asm read my message again. I was talking about theoretical maximum performance Comment deleted
Ok, but I’m talking about real projects.. in real life it’s almost impossible to outperform well-written C built with profiling Comment deleted
nobody argued with that Comment deleted
There’s just no way you can have that amount of info to incorporate all the knowledge about real execution paths on real data that the compiler would gather Comment deleted
The abstract theory is another question.. Comment deleted
With LLVM it compiles to an intermediate representation which would then have additional optimization stages. Same as if you write it in C with Clang Comment deleted
Great discussion 😊 Comment deleted
sorry, I'll stop Comment deleted
It’s just closer to bare-metal binary code than C, but that’s it, it’s not the binary code Comment deleted
It’s close enough I’d say.. also, the way it executes inside of the CPU is yet another question/issue.. Comment deleted
anyway, end of discussion, this won't lead us anywhere Comment deleted
At least for me, this was very interesting. I wish I had teachers like Anatoli and you in college, discussing different points of view on the same subject. Comment deleted
ah? well, I'm glad you liked the discussion, but I sure didn't :/ I often get myself into these debates despite not liking them. Comment deleted
cause I'm stubborn and dislike being wrong, which is an unfortunate combo to have as an introvert Comment deleted
In this case yes, C code would be slower than asm code Comment deleted
But I’m not sure why would someone consider that Comment deleted
just for fun - it's like comparing the top speed of cars. In the real world, they're never gonna reach that speed, but it's fun to compare them Comment deleted
Ok, for that case I agree. But if we see the practical performance aspects of different languages, then IMO Rust is the fastest one, then goes C and then asm. The constraints here are the limited knowledge of.. say.. a team of senior devs and a limited time they have to develop a real-world piece of software that works on real-world data supplied to it by real-world users.. Comment deleted
agreed, that definitely makes sense, although I think it's important to note that Rust is a lot newer than C which means there are less existing frameworks, which may hinder development. In any way C and Rust are very different languages, and I don't like to compare them directly in the context of real-world scenarios because I'm really not knowledgeable enough to do that. Comment deleted
😏 I guess today there’s much more tooling and really reusable libs in Rust than ever in the history of C. There was no single time that I couldn’t find some lib for a generic functionality like JSON parsing or a HTTPstand-alone server in https://lib.rs. In C the largest problem always was the lack of reusable (in practice) libs. The Rust crates is a godsent aspect of the language for C devs Comment deleted
Hahaha. Don't take it personal, you are talking about theoretical programmers programming on theoretical processors. It doesn't get less personal than that. Also, I've seen Anatoli giving lectures in conventions, and he knows a shit-ton. It's always interesting challenging a knowledgeable person and understanding their reasoning. Comment deleted
The point here is that good C compliers like modern CLang/LLVM and gcc have more knowledge about the underlying hardware incorporated in them that a typical senior devs team would have. So it (the compiler) has a better understanding of how to translate the developers intentions into the bytecode, taking into account the cache sizes, the number of CPU pipelines and how the instructions are getting processed inside the CPU, to avoid stale pipelines, cache misses, etc that compared to say 2-3 additional asm instructions are 3-4 orders of magnitude bigger issues.. Comment deleted
And if you perform an instrumented profiling of your C code, where the compiler instruments your code in order to collect the real-data execution paths metrics and then execute the binary on real-world data to collect the metrics, then recompile it feeding the compiler this statistics, that it would know about such situations that you couldn’t even suppose can happen. In this case it would be able to optimize the code even better, and except some really simple code like 10 lines of C, you won’t be able to outsmart the compiler Comment deleted
didn't even know compilers could take metrics into account, you learn something new every day I guess Comment deleted
https://en.m.wikipedia.org/wiki/Profile-guided_optimization Comment deleted
thanks for the link, I'll bookmark it to read tomorrow morning Comment deleted
I was working in HPC projects asm hand-coding for about 8 years (around 2004), for IBM BlueGene/L supercomputer and x86 megaclusters of 500+ nodes.. was holding the details of almost the entire Intel Instructions Set in brain.. but then SSE instructions appeared, caches got bigger, more CPU pipelining and smarter CPU tricks to execute the instructions.. so to outsmart the compiler with profile-guided optimizations became a task not worth the effort.. say 5% faster spending months on performance tuning the project.. and then the compilers became even smarter, the CPUs even more complex so I quit the asm performance tuning as it made no sense Comment deleted
ah, see, I didn't have time in 2004 as I was busy being born lol Respect, man, sounds like you're an elite professional. Comment deleted
😆 thanks Comment deleted
damn I can't keep up with your walls of text 😅 Comment deleted
basically it's not all that clear now Comment deleted
to get good perf you actually have to use quite alot of unsafe, risking ub Comment deleted
also, compared to c++ rust's meta sucks Comment deleted
Why so? Do you have a link to read about the details? Comment deleted
consider this example: suppose you have a function that fails very rarely, the rust way is to make that function return a Result, but that actually incurs a cost on the happy path, bc you have to have an if even if your Result is Ok, on the other hand, if you user exceptions, you can avoid that if and save time on the happy path Comment deleted
also there are times where you have to perform runtime checks to ensure safety, bc rust's type system sucks, whereas in c++ you could just make it not compile Comment deleted
But exceptions are not free either Comment deleted
yeah, it's a tradeoff Comment deleted
better to have both Comment deleted
But the “if” is just a single tick if you guess the result, do you know that? Comment deleted
i know that, but it's worse than none Comment deleted
Also a single tick doesn’t matter at all if it’s not inside some absolutely EPIC cycle, and you’re talking about saving it on func exit, that implies a number of stack reads, which could result in cache misses, so your tick is just lost in the cache misses delays and pipeline stales causing hundreds of ticks delay.. Comment deleted
the question is when Comment deleted
👆you say that the Rust way to check the result is inefficient and you should recure to unsafe Rust to "fix" it Comment deleted
nope, that's not at all what i told Comment deleted
i told that you want both options Comment deleted
With respect to Rust outperforming C, the point here is that the Rust compiler has much more knowledge about your intentions that if you write the code in C, so it can make assumptions the C compiler can’t. And with these assumptions it can optimize it even further. On the other hand, it’s much easier to write performant code in Rust than in C, not to say that in C you just never have time for the optimizations as your are constantly debugging it investigating strange crushes, especially when multithreading and coding non-trivial stuff Comment deleted
So in practical terms your real-world Rust code is almost guaranteed to outperform your real-world C code Comment deleted
If you haven’t seen it yet, I suggest you check this short online book about Rust performance tuning: https://nnethercote.github.io/perf-book/ Comment deleted
😄 yeah Rust was godsent to the C devs that were suffering for decades.. Comment deleted
now life is great again Comment deleted
I mean, under no circumstances would I make my code that ugly to save a single tick! Comment deleted
as of today, you don't have an option Comment deleted
even if you liked to Comment deleted
If you have a single cache miss its like 150 ticks Comment deleted
If you stale the pipeline with some unordered instruction it could lead to multiple cache misses Comment deleted
I just trust the compiler to handle all that stuff.. you never win by saving a tick.. been there, quit it Comment deleted
it's a small example that i thought up off the top of my head Comment deleted
btw, on the topic of error handling, tho it's more about expressiveness and not perf: why isn't there a std::variant analog in rust? you literally can't live without it in result based error handling world Comment deleted
I mean this is not the way you optimize your code Comment deleted
The 2 most critical performance issues on the CPU level are the cache misses and the pipeline stales Comment deleted
with exceptions, when do they happen? Comment deleted
they happen only on the sad path, not on the happy one Comment deleted
Have you ever coded in asm? Comment deleted
yes Comment deleted
Then what do you mean about the things happening on a happy path and not happening in the sad path? Comment deleted
when exception is/is not thrown Comment deleted
How do you implement a condition check in asm? Comment deleted
with a conditional jump (eg. jne), cmov may actually be an option sometimes too Comment deleted
If the result is in eax and 0 means no errors, the code would be: test eax, eax jnz error_handling Comment deleted
yes, callee side, but caller side ou don't have to do anything Comment deleted
oh fuck, a test, not a branch Comment deleted
there is a test instruction, and arithmetic ops write to the flag register too Comment deleted
https://gcc.godbolt.org/z/Thh8YcWaT an example Comment deleted
Exceptions are on the much higher level, in the C code.. but as you’re talking about saving a single if which is a conditional jump in asm like (je/jz) which’s is 1 tick (CPU cycle) on right guess and 3 ticks on wrong guess (right means you specify it in such a way that most of the times the jump is not performed), I’m showing you the underlying considerations worth much more than trying to save a single if. Comment deleted
And as it was pointed before, exceptions are basically the same ifs, but more complex on the asm instructions level, so it’s not clear what would be faster.. a simple je (if in asm) or some non-trivial exceptions checking Comment deleted
Check here for relative latenixes of cache misses: https://stackoverflow.com/questions/1126529/what-is-the-cost-of-an-l1-cache-miss#29188516 Comment deleted
oh, i remembered one more thing: allocating a large object on the heap involves memcpying it off the stack first Comment deleted
well, all objects, but this matters for the particularly large ones Comment deleted
Are you sure you fully understand this stuff? Comment deleted
well, unless you actually intend on handling the error Comment deleted
You always have to make a check.. if not, you can’t know if you have an error condition or not Comment deleted
look at the example Comment deleted
So compare the code you suggest of an exception: thrw(bool) [clone .cold]: .L3: mov edi, 4 call __cxa_allocate_exception xor edx, edx mov esi, OFFSET FLAT:_ZTIi mov DWORD PTR [rax], 43 mov rdi, rax call __cxa_throw with a result check code: test eax, eax jnz error_handling and tell me what's faster Comment deleted
do you see the cold Comment deleted
didn't i already tell you that it's efficient only when errors are rare? Comment deleted
you can even turn off the optimizations and see that there is a call and then an immediate leave Comment deleted
well, actually, afaik rust already uses this mechanism for unwind panics Comment deleted
unwind panics are entirely different stuff that what was your initial suggestion for optimization Comment deleted
they are the same mechanism Comment deleted
same mechanism as the C exceptions, but you proposed another thing initially Comment deleted
c exceptions? Comment deleted
And I'm saying that a simple result check is just 1 tick of the CPU time Comment deleted
a simple results check is the least expensive option of all Comment deleted
you simply refuse to see that sth like ? operator is free as in no if with exceptions Comment deleted
🤔 could you please provide the asm code for both cases? I guess I don't understand what you mean.. Comment deleted
https://gcc.godbolt.org/z/TYWMEKPco here, with one more fnction Comment deleted
look at thrw2, see no if Comment deleted
what do you mean no if? I don't understand what you propose.. i.e. there is a func in rust that returns something as a Result and you should check it for errors in the outer function.. this would be as simple as: test eax, eax jnz error_handling Comment deleted
https://gcc.godbolt.org/z/K3zvMKn6n Comment deleted
wait no, it's not good yet Comment deleted
no RAM involved, no cache misses Comment deleted
then you suggest a huge and complex code with function calls that involve writing to RAM invalidating your caches, which implies cache misses, etc.. and you're saying it's faster? don't understand your point Comment deleted
it's only in rare cases, i repeat Comment deleted
look at res2 now Comment deleted
do you mean this code is fast? Comment deleted
https://gcc.godbolt.org/z/1118bMj9K added math to illustrate a point Comment deleted
and what would be the equivalent in Rust? Comment deleted
https://gcc.godbolt.org/z/M54rzeMnr Comment deleted
now take a look at res2 vs thrw2 Comment deleted
also take a look at that cmov, which will never be just 1 tick Comment deleted
add there a main, call there the necessary func and let's see the total cost of execution in both cases Comment deleted
well, i'll leave it as an excersise for you, as i am alre in bed Comment deleted
😆 thanks, done those exercises 25 years ago Comment deleted
write its alternative in Rust and compare Comment deleted
if you can't see the clear difference in favor of Rust from your own examples, the only thing that can help is if you calculate the total cost of execution of your examples and compare 2 numbers Comment deleted
ofc if the probability of that bool being false is 50% then ofc rust wins, but if it's more like 0.1% then you better bet c++ will win Comment deleted
just add main() to Rust, in both Rust and C put there a loop of say 1M iterations of calling the func you want to prove, then compile and run both binaries and see the result Comment deleted
run them this way: $ time rust_bin and $ time c_bin Comment deleted
that won't work tho Comment deleted
now tell me why just time won't work Comment deleted
you say it won't work, you say why it won't work Comment deleted
a question: does a program really start in main? Comment deleted
are you running a basic asm quiz? Comment deleted
no asm Comment deleted
you don't have to know it to answer Comment deleted
and answer why that won't work Comment deleted
i've already spent toooooo much time discussing with you that basic stuff.. if you want to prove your point, provide here the same code in both C and Rust that compiles and runs without fixing it.. and we'll see the results Comment deleted
now Comment deleted
what was the disputed claim? holy fuck Comment deleted
Funniest part was looking at this meme and seeing "197 comments" Comment deleted
take a look at theese srcs Comment deleted
need your confirmation fefore i reveal the numbers Comment deleted
using vec for a for loop.. Comment deleted
otherwise it's inlined away, and to be fair it's done in c++ and rust equally Comment deleted
this makes the program like 100 times (or more) slower Comment deleted
i don't have time right now, but just for fun, this weekend I'll send you a correctly coded rust code Comment deleted
Vec for loop is q is a construct known to be extremely slow compared yo a simple int loop Comment deleted
I don't have an int loop in c++ tho Comment deleted
Are you testing the Result handling performance or a vec enumeration performance?? Comment deleted
vec iteration is only there to prevent inlining, if you have a better idea be my guest Comment deleted
And BTW your code is extremely convoluted.. all the time counting code should not be there Comment deleted
are you sure you don't want to compare allocation performance? Comment deleted
90% of what you put in the cpp is not needed Comment deleted
You claimed that the Result check is slower than exceptions Comment deleted
So let’s check your claim first Comment deleted
Then you can make a new claim and we’ll see if you’re right or not Comment deleted
The thing is simple: you make a for loop with ints in both cases and put there the check Comment deleted
this is also compiled away Comment deleted
It doesn’t matter how the loop ends implemented in bytecode, we are not testing the loop, it’s just to repeat the same check many times as a single check won’t show the difference Comment deleted
it caches the result and compiles away the loop entierly Comment deleted
And it also doesn’t matter the inlining.. we are testing the default compilation without anything special about it.. cc x.cpp and rustc main.rs Comment deleted
so no optimizations? Comment deleted
Exactly, no special optimizations (but the code do should be well written, i.e. with known good constructs), no pragmas, inlines & co, just the basic code of try/catch vs Result check and a basic int loop for enough iterations for the execution to last for some 5 seconds to make the process start statistically negligible Comment deleted
did you try to read unoptimized rust? Comment deleted
The most simple code in both cases Comment deleted
Should be like 10 lines of code at most Comment deleted
So when you measure the time with time the measurement is just of the loop itself Comment deleted
rust 0.38s user 0.00s system 99% cpu 0.385 total cpp 0.04s user 0.00s system 99% cpu 0.048 total which is bs bc why the fuck would you want all optimizations off in the first place Comment deleted