adding explaination of volatile

This commit is contained in:
Jidong Xiao
2025-02-24 22:17:23 -05:00
committed by JamesFlare
parent f7f69ecd2f
commit 33c771a3a5

View File

@@ -11,27 +11,33 @@ $ sudo apt-get install binutils
## Compiling a C++ Program for Profiling
To use `gprof`, compile your program with the `-pg` flag:
```sh
$ g++ -pg -o my_program my_program.cpp
$ g++ -pg -o test test.cpp
```
## Example C++ Program
Create a file `my_program.cpp` with the following code:
Create a file `test.cpp` with the following code:
```cpp
#include <iostream>
#include <chrono>
#include <thread>
void slowFunction() {
std::this_thread::sleep_for(std::chrono::seconds(1));
void heavyComputation() {
volatile long long sum = 0;
for (long long i = 0; i < 500000000; ++i) {
sum += i; // Simple but expensive loop
}
}
void fastFunction() {
for (volatile int i = 0; i < 1000000; ++i);
void lightComputation() {
volatile int sum = 0;
for (int i = 0; i < 100000; ++i) {
sum += i; // Lighter loop
}
}
int main() {
for (int i = 0; i < 5; ++i) slowFunction();
for (int i = 100; i < 200; ++i) fastFunction();
heavyComputation(); // Call heavy function once
for (int i = 0; i < 1000; ++i) {
lightComputation(); // Call light function many times
}
return 0;
}
```
@@ -39,15 +45,15 @@ int main() {
## Running and Profiling the Program
1. Compile the program:
```sh
$ g++ -pg -o my_program my_program.cpp
$ g++ -pg -o test test.cpp
```
2. Execute the program to generate `gmon.out`:
```sh
$ ./my_program
$ ./test
```
3. Analyze the profiling data:
```sh
$ gprof my_program gmon.out > profile.txt
$ gprof test gmon.out > profile.txt
$ cat profile.txt
```
@@ -62,3 +68,54 @@ int main() {
## Conclusion
`gprof` is a powerful tool for detecting performance bottlenecks in C++ programs. By identifying expensive functions, developers can make targeted optimizations.
# Why Use `volatile` in the above program?
## Compiler May Remove the Loops
When compiling a program, the compiler applies optimizations to make the code run faster. One such optimization is **dead code elimination**, where the compiler removes code that does **not affect the program's observable behavior**.
For example, consider this function:
```cpp
void heavyComputation() {
long long sum = 0;
for (long long i = 0; i < 500000000; ++i) {
sum += i;
}
}
```
- The compiler notices that `sum` is **never used outside the function**.
- Since the result is discarded, the compiler **may completely remove the loop**.
- This means `heavyComputation()` might do **nothing** at runtime, which ruins our profiling experiment.
---
## How Does `volatile` Help?
Declaring a variable as `volatile` tells the compiler:
"This variable might change in ways you cannot predict, so do not optimize it away."
For example:
```cpp
void heavyComputation() {
volatile long long sum = 0; // Mark sum as volatile
for (long long i = 0; i < 500000000; ++i) {
sum += i;
}
}
```
- Now, **even if `sum` is never used**, the compiler **must** perform the loop.
- The `volatile` keyword prevents the compiler from assuming that `sum` is unimportant.
- This ensures that the loop actually runs during profiling.
---
## **Does `volatile` Affect Performance?**
Yes, but only slightly.
- **Without `volatile`**, the compiler can optimize the loop aggressively.
- **With `volatile`**, every read and write to `sum` is guaranteed to happen exactly as written, preventing some optimizations.
However, this small cost is **worth it for benchmarking**, because it ensures that the loops are not removed.