Keywords: C++ | File I/O | Performance Optimization | Binary Files | SSD Writing
Abstract: This paper comprehensively explores performance optimization methods for writing large binary files (e.g., 80GB data) efficiently in C++. Through comparative analysis of two main I/O approaches based on fstream and FILE, combined with modern compiler and hardware environments, it systematically evaluates the performance of different implementation schemes. The article details buffer management, I/O operation optimization, and the impact of compiler flags on write speed, providing optimized code examples and benchmark results to offer practical technical guidance for handling large-scale data writing tasks.
Introduction
In modern computing applications, scenarios involving large-scale datasets are increasingly common, particularly in scientific computing, big data analytics, and storage systems. Efficiently writing massive amounts of data to persistent storage devices has become a critical performance bottleneck. Based on a practical case, this paper explores how to optimize the performance of writing large binary files in C++, specifically in Solid State Drive (SSD) environments.
Problem Background and Initial Implementation
The original problem involved writing 80GB of data to an SSD, with an initial implementation using std::fstream from the C++ Standard Library:
#include <fstream>
const unsigned long long size = 64ULL * 1024ULL * 1024ULL;
unsigned long long a[size];
int main() {
std::fstream myfile;
myfile = std::fstream("file.binary", std::ios::out | std::ios::binary);
for (int i = 0; i < 32; ++i) {
myfile.write((char*)&a, size * sizeof(unsigned long long));
}
myfile.close();
}
This implementation achieved only about 20MB/s write speed in a Windows 7 environment, far below the theoretical performance of SSDs (150-200MB/s). The performance bottleneck primarily stemmed from frequent I/O operations and potential buffer management issues.
Optimization Solution: FILE-Based Implementation
By switching to the C Standard Library's FILE interface, performance was significantly improved:
#include <stdio.h>
const unsigned long long size = 8ULL * 1024ULL * 1024ULL;
unsigned long long a[size];
int main() {
FILE* pFile = fopen("file.binary", "wb");
for (unsigned long long j = 0; j < 1024; ++j) {
fwrite(a, 1, size * sizeof(unsigned long long), pFile);
}
fclose(pFile);
return 0;
}
This implementation reduced the write time for 8GB of data to 36 seconds, increasing speed to approximately 220MB/s, while CPU usage dropped from 100% to 2-5%. Key optimization points include:
- Using larger buffers to reduce system call frequency
fwrite's batch processing capability outperformsstd::fstream::write- Avoiding the overhead of C++ stream objects
Performance Re-evaluation in Modern Environments
With the evolution of compilers and technology stacks, tests in 2017 showed that std::fstream performance had significantly improved:
#include <fstream>
#include <chrono>
#include <vector>
#include <cstdint>
std::vector<uint64_t> GenerateData(std::size_t bytes) {
std::vector<uint64_t> data(bytes / sizeof(uint64_t));
// Data generation logic
return data;
}
long long option_1(std::size_t bytes) {
auto data = GenerateData(bytes);
auto start = std::chrono::high_resolution_clock::now();
auto file = std::fstream("file.binary", std::ios::out | std::ios::binary);
file.write((char*)&data[0], bytes);
file.close();
auto end = std::chrono::high_resolution_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
}
// Similar implementations for option_2 (FILE) and option_3 (sync_with_stdio(false))
Test results indicated that, with modern compilers and optimization flags, std::fstream could achieve the maximum performance of SSDs, comparable to the FILE implementation.
Analysis of Key Optimization Techniques
Buffer Size Optimization: Appropriately increasing buffer size can reduce the number of I/O operations, but a balance must be struck between memory usage and performance gains.
Compiler Optimization Flags: Flags such as g++'s -O3 and Visual Studio's /Ox significantly improve code generation quality.
Standard Library Selection: std::ios_base::sync_with_stdio(false) disables synchronization between C++ and C I/O, reducing overhead.
Memory Management: Using std::vector instead of raw arrays provides better memory safety and flexibility.
Performance Comparison and Conclusion
Comprehensive test data shows:
- Original
std::fstreamimplementation: ~20MB/s - Optimized
FILEimplementation: ~220MB/s - Modern
std::fstreamimplementation: Reaches SSD maximum speed
The conclusion indicates that in modern C++ development, std::fstream has become a viable option for high-performance file I/O, especially when combined with appropriate compiler optimizations and buffer strategies.
Practical Recommendations
For large-scale data writing scenarios:
- Prioritize testing different I/O methods in the target environment
- Use modern C++ features (e.g., RAII) to ensure resource safety
- Consider asynchronous I/O or memory-mapped files for extreme performance needs
- Regularly update compilers and standard libraries to leverage the latest optimizations