In my previous post, I have tested journal writing techniques on Linux, in this post, I want to do the same for Windows, and see what the impact of the various options are the system performance.
Windows has slightly different options than Linux. In particular, in Windows, the various flags and promises and very clear, and it is quite easy to figure out what is it that you are supposed to do.
We have tested the following scenarios
- Doing buffered writes (pretty useless for any journal file, which needs to be reliable, but good baseline metric).
- Doing buffered writes and calling FlushFileBuffers after each transaction (which is pretty common way to handle committing to disk in databases), and the equivalent of calling fsync.
- Using FILE_FLAG_WRITE_THROUGH flag and asking the kernel to make sure that after every write, everything will be flushed to disk. Note that the disk may or may not buffer things.
- Using FILE_FLAG_NO_BUFFERING flag to bypass the kernel’s caching and go directly to disk. This has special memory alignment considerations
- Using FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING flag to ensure that we don’t do any caching, and actually force the disk to do its work. On Windows, this is guaranteed to ask the disk to flush to persisted medium (but the disk can ignore this request).
Here is the code:
We have tested this on an AWS macine ( i2.2xlarge – 61 GB, 8 cores, 2x 800 GB SSD drive, 1GB /sec EBS), which was running Microsoft Windows Server 2012 R2 RTM 64-bits. The code was compiled for 64 bits with the default release configuration.
What we are doing is write 1 GB journal file, simulating 16 KB transactions and simulating 65,535 separate commits to disk. That is a lot of work that needs to be done.
First, again, I run it on the system drive, to compare how it behaves:
Method | Time (ms) | Write cost (ms) |
Buffered |
396 |
0.006 |
Buffered + FlushFileBuffers |
121,403 |
1.8 |
FILE_FLAG_WRITE_THROUGH |
58,376 |
0.89 |
FILE_FLAG_NO_BUFFERING |
56,162 |
0.85 |
FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING |
55,432 |
0.84 |
Remember, this is us running on the system disk, not on the SSD drive. Here are those numbers, which are much more interesting for us.
Method | Time (ms) | Write cost (ms) |
Buffered |
410 |
0.006 |
Buffered + FlushFileBuffers |
21,077 |
0.321 |
FILE_FLAG_WRITE_THROUGH |
10,029 |
0.153 |
FILE_FLAG_NO_BUFFERING |
8,491 |
0.129 |
FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING |
8,378 |
0.127 |
And those numbers are very significant. Unlike the system disk, where we basically get whatever spare cycles we have, in both Linux and Windows, the SSD disk provides really good performance. But even on identical machine, running nearly identical code, there are significant performance differences between them.
Let me draw it out to you:
Options |
Windows |
Linux |
Difference |
Buffered |
0.006 |
0.03 |
80% Win |
Buffered + fsync() / FlushFileBuffers() |
0.32 |
0.35 |
9% Win |
O_DSYNC / FILE_FLAG_WRITE_THROUGH |
0.153 |
0.29 |
48% Win |
O_DIRECT / FILE_FLAG_NO_BUFFERING |
0.129 |
0.14 |
8% Win |
O_DIRECT | O_DSYNC / FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING |
0.127 |
0.31 |
60% Win |
In pretty much all cases Windows has been able to out perform Linux on this specific scenario. In many cases by a significant margin. In particular, in the scenario that I actually really care about, we see 60% performance advantage to Windows.
One of the reasons for this blog post and the detailed code and scenario is the external verification of these numbers. I’ll love to know that I missed something that would make Linux speed comparable to Windows, because right now this is pretty miserable.
I do have a hunch about those numbers, though. SQL Server is a major business for Microsoft, so they have a lot of pull in the company. And SQL Server uses FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING internally to handle the transaction log it uses. Like quite a bit of other Win32 APIs (WriteGather, for example), it looks tailor made for database journaling. I’m guessing that this code path has been gone over multiple times over the years, trying to optimize SQL Server by smoothing anything in the way.
As a result, if you know what you are doing, you can get some really impressive numbers on Windows in this scenario. Oh, and just to quite the nitpickers: