RAD Studio is made up of Delphi and C++Builder. On the Delphi side the Object Pascal compiler is a single pass compiler and the compiler itself is not a parallel compiler but when compiling multiple projects in parallel it was able to compile 1 billion lines of Object Pascal code in 5 minutes on the AMD Ryzen 9 5950x 16 core machine. I wanted to see if something similar was possible with C++. This post is part of our modern hardware series where we explore the massive productivity gains that can be achieved on some of the fastest CPUs available at the time of this writing in early 2021. Just how much is 1 billion lines of code? Take a look.
Parallel Compilation In C++Builder
C++Builder has a number of different compilers including the classic Borland compiler and modern Clang based compilers for a number of platforms. Additionally, Embarcadero sponsors the open source Dev-C++ which has the TDM-GCC 9.2.0 compiler bundled with it. GCC 9.2.0 comes with MAKE which supports handles parallel compilation through it’s -j (Jobs) command line switch. C++Builder has an add-on called TwineCompile that brings parallel compilation to C++Builder. Both C++Builder and Dev-C++ are built with Delphi.
During my investigations so far TwineCompile seems to offer more functionality than MAKE Jobs because TwineCompile supports background compilation and some other productivity enhancing features. It is up to to the IDE (Dev-C++) to support additional features like background compilation but at this time Dev-C++ does not while C++Builder does through TwineCompile. Dev-C++ is a great native C++ IDE for Windows development and then C++Builder turns the productivity up to the max with it’s visual designer, powerful built in VCL RTL, and enhanced parallel compilation features. Additionally, they are based around the different C++ compilers so it is not entirely a direct comparison and they really compliment each other.
Third party benchmarks (not the project in this blog post) for a 3990X with TwineCompile:
- Machine specs: AMD® Ryzen® Threadripper 3990X (2.9 ghz, 64 cores, 128 threads)
- Configuration: IDE Compile.
- Results: Without TwineCompile With TwineCompile
- 3:35:02 hours:minutes:seconds 0:05:44 hours:minutes:seconds
Parallel Compilation In Dev-C++
At the beginning of this quest Dev-C++ did not support the -j MAKE flag so that was the first task to complete. I was able to update Dev-C++ and release the new v6.3 version with the parallel compilation -j built-in as an option now. It is also on by default for release builds so that should greatly reduce compile times for everyone using Dev-C++. The update had to be made because the command line flag that needed to be added had to be added to MAKE and not to the compiler command line. This took a few days to implement and get the new v6.3 version released. Bundled in with this release was all the bug fixes from the last two months and a second new feature where custom embedded console apps can be selected. Here are the release notes for Dev-C++ v6.3:
Version 6.3 – 30 January 2021
- Added: Parallel compilation enabled by default for release builds through MAKE Jobs.
- Added: 3 Buttons for setting up custom shell command line tabs.
- Updated: Code completion and menues for dark themes.
- Updated: CTRL-TAB editor tab selection wrapping.
- Fixed: Make clean file deletion issue.
- Fixed: Status bar not showing all text.
- Fixed: Debug/CPU Window hex column issue.
- Fixed: Closing tabs in editor side by side view.
Once I had the Dev-C++ IDE that could parallel compile the 1 billion lines of C++ I needed the actual AMD Threadripper 3990X with the 64 cores and 128 threads. The Threadripper scores less per CPU on PassMark than the 5950X but because it has more cores it has a higher overall score. The below screenshot is from PassMark showing a comparison of the two CPUs. As you can see the 5950x has a single core benchmark of 3491 while the 3990x has a single core benchmark of 2553. But the 3990x has a overall multicore benchmark of 80752 right now while the 5950x only has a multicore benchmark of 46045 right now.
ReliableSite.net has cloud based AMD Threadripper 3990X 256GB of RAM machines which fit the needs of this project. They offer two different Windows setups: Windows Standard 2016 and Windows Standard 2019. I selected Windows 2016 and they tried to install the machine with that OS but for whatever release were unable to due to most likely a licensing issue with how Microsoft has the licensing of CPUs and cores in Windows Standard 2016. In any event, they switched it to Windows Standard 2019 and it was able to install just fine.
At this point we are up and running on the Threadripper Windows 2019 machine with C++Builder and TwineCompile plus Dev-C++ v6.3 with it’s new parallel compilation support built-in. Everything tests out and runs great. C++Builder is able to compile the 1 million lines of C++ from a previous post 4X faster than the 5950x did and Delphi is able to compile the 1 billion lines of Object Pascal projects 2.5X faster as well. We’ll leave those two comparisons for another post.
One of the tools I use with the modern hardware posts to gauge the CPU usage is Task Manager DeLuxe from MiTeC. Task Manager DeLuxe is pretty amazing in the amount of information it provides regarding your Windows system. TMX features a dark (very 2021) and light mode. TMX is available from MiTeC which also makes a wide variety of Delphi components that give you access to a lot of the same information found in TMX. Most of the information in TMX is probably available for you to use in your app with the MiTeC System Information Component Suite.
When I first loaded Task Manager DeLuxe up on the Threadripper 3990x 64 core machine it was not able to display the individual CPU graphs and threw out an error. I have a commercial license to Task Manager DeLuxe so I sent an email to Michal at MiTeC and he was able to solve the issue very quickly. He released a new version of Task Manager DeLuxe which now loads up and runs great on the 64 core machine.
The next task was to actually create the 1 billion lines of code C++ project so we can compile it. I started out with this Scimark2 project for Dev-C++ and developed a Delphi app to quickly generate the number of lines of code needed. In the end I wanted to be able to actually run the application created from the 1 billion lines of C++. The Delphi app takes the LU.c and LU.h files and duplicates the last function LU_factor() the number of times needed to create the designed number of lines. The function itself is 69 lines long and to avoid name collisions each generated function has a file number and a iterator number.
I tried a number of different ways to slice the C++ project files up with more files and less lines or more lines and less files. In the Delphi project I did 4 million lines across 250 different projects. For the C++ project one of the ways was with 32,000 files and 31,250 lines per file. I arrived at this number with some testing because it seemed like Dev-C++ did better with smaller files, more files for more cores, and a great number of smaller files mimics a real project more closely. A second way was with 10,666 files and 93,750 lines per file. A third way is with 1000 files and 1000000 lines of C++ per file. The list of files gets added to the Dev-C++ project file after they have been generated which means Dev-C++ has to load that list of files into its project list.
A bottleneck I discovered here is that Dev-C++ has code completion and symbol completion. These features parse the files in the project when the project is opened and suffice to say they are not parallelized yet. Dev-C++ does eventually load but it takes awhile for it to handle the 32,000 files (and even the 10,666 files). Once I figured this out I was able to disable the code completion and symbol completion which allows the 1 billion lines of C++ code project to load quickly. Dev-C++ doesn’t seem to have any trouble editing a file with 1 million lines and it feels pretty snappy.
A second issue I ran into is that Delphi’s System.CPUCount procedure reports 32 instead of the 128 threads. 32 cores might have been enough when the System.CPUCount procedure was written but we’re way beyond that now. In the case of the 5950X which has 16 cores and 32 threads the procedure works great but for the 3990X this was incorrect. I reported this issue to the Embarcadero Quality portal but in the mean time there is a third party NumCPULib4Pascal library which should report the correct value. I built a custom build of the Dev-C++ executable and hard coded in the 128 threads for now.
We’re almost ready to go for the 1 billion lines of code compile now! We have the hardware in place, we have the IDE, and the compilers in place, and we have the projects (slices different ways in place). I have been compiling different size versions of the 1 billion lines of C++ project during the whole process to figure out each of the issues mentioned above and correct them.
Let’s start out with the 1 billion line project split into 32,000 files with 31,250 lines each. This project compiles. It uses all of the cores as it should but when it gets down to linking the 32,000 files into the executable it stalls out. There is a limit on the command line for being able to pass the 32,000 files to the linker. The maximum length of the Windows command line is 32768 bytes which is a USHORT in the Windows API. The second project with the 10,666 files and 93,750 lines per file also compiles but fails out for the same reason.
The third project with the 1000 files and 1,000,000 lines per file compiles as well but more slowly. It does not use all 128 cores during the compilation process. Selecting -j64, -j128, and -j (automatic) from MAKE sees only around ~34 of the 64 cores really fire up though it does execute 64 g++ processes. It uses 81GB of RAM during this process so it’s a good thing the machine has 256GB of RAM. Once all of the files compile it does get past executing the command line but the linker itself crashes out with an error while it is trying to combine all of the object files into the executable. So far the suggestions found on StackOverflow of various command line arguments to pass did not solved the issue.
g++.exe scimark2.o FFT.o LU.o MonteCarlo.o SOR.o SparseCompRow.o Stopwatch.o Random.o kernel.o array.o LU0.o LU1.o LU2.o LU3.o LU4.o LU5.o LU6.o LU7.o LU8.o LU9.o LU10.o LU11.o LU12.o LU13.o LU14.o LU15.o LU16.o LU17.o LU18.o LU19.o LU20.o LU21.o LU22.o LU23.o LU24.o LU25.o LU26.o LU27.o LU28.o LU29.o LU30.o LU31.o LU32.o LU33.o LU34.o LU35.o LU36.o LU37.o LU38.o LU39.o LU40.o LU41.o LU42.o LU43.o LU44.o LU45.o LU46.o LU47.o LU48.o LU49.o LU50.o LU51.o LU52.o LU53.o LU54.o LU55.o LU56.o LU57.o LU58.o LU59.o LU60.o LU61.o LU62.o LU63.o LU64.o LU65.o LU66.o LU67.o LU68.o LU69.o LU70.o LU71.o LU72.o LU73.o LU74.o LU75.o LU76.o LU77.o LU78.o LU79.o LU80.o LU81.o LU82.o LU83.o LU84.o LU85.o LU86.o LU87.o LU88.o LU89.o LU90.o LU91.o LU92.o LU93.o LU94.o LU95.o LU96.o LU97.o LU98.o LU99.o LU100.o LU101.o LU102.o LU103.o LU104.o LU105.o LU106.o LU107.o LU108.o LU109.o LU110.o LU111.o LU112.o LU113.o LU114.o LU115.o LU116.o LU117.o LU118.o LU119.o LU120.o LU121.o LU122.o LU123.o LU124.o LU125.o LU126.o LU127.o LU128.o LU129.o LU130.o LU131.o LU132.o LU133.o LU134.o LU135.o LU136.o LU137.o LU138.o LU139.o LU140.o LU141.o LU142.o LU143.o LU144.o LU145.o LU146.o LU147.o LU148.o LU149.o LU150.o LU151.o LU152.o LU153.o LU154.o LU155.o LU156.o LU157.o LU158.o LU159.o LU160.o LU161.o LU162.o LU163.o LU164.o LU165.o LU166.o LU167.o LU168.o LU169.o LU170.o LU171.o LU172.o LU173.o LU174.o LU175.o LU176.o LU177.o LU178.o LU179.o LU180.o LU181.o LU182.o LU183.o LU184.o LU185.o LU186.o LU187.o LU188.o LU189.o LU190.o LU191.o LU192.o LU193.o LU194.o LU195.o LU196.o LU197.o LU198.o LU199.o LU200.o LU201.o LU202.o LU203.o LU204.o LU205.o LU206.o LU207.o LU208.o LU209.o LU210.o LU211.o LU212.o LU213.o LU214.o LU215.o LU216.o LU217.o LU218.o LU219.o LU220.o LU221.o LU222.o LU223.o LU224.o LU225.o LU226.o LU227.o LU228.o LU229.o LU230.o LU231.o LU232.o LU233.o LU234.o LU235.o LU236.o LU237.o LU238.o LU239.o LU240.o LU241.o LU242.o LU243.o LU244.o LU245.o LU246.o LU247.o LU248.o LU249.o LU250.o LU251.o LU252.o LU253.o LU254.o LU255.o LU256.o LU257.o LU258.o LU259.o LU260.o LU261.o LU262.o LU263.o LU264.o LU265.o LU266.o LU267.o LU268.o LU269.o LU270.o LU271.o LU272.o LU273.o LU274.o LU275.o LU276.o LU277.o LU278.o LU279.o LU280.o LU281.o LU282.o LU283.o LU284.o LU285.o LU286.o LU287.o LU288.o LU289.o LU290.o LU291.o LU292.o LU293.o LU294.o LU295.o LU296.o LU297.o LU298.o LU299.o LU300.o LU301.o LU302.o LU303.o LU304.o LU305.o LU306.o LU307.o LU308.o LU309.o LU310.o LU311.o LU312.o LU313.o LU314.o LU315.o LU316.o LU317.o LU318.o LU319.o LU320.o LU321.o LU322.o LU323.o LU324.o LU325.o LU326.o LU327.o LU328.o LU329.o LU330.o LU331.o LU332.o LU333.o LU334.o LU335.o LU336.o LU337.o LU338.o LU339.o LU340.o LU341.o LU342.o LU343.o LU344.o LU345.o LU346.o LU347.o LU348.o LU349.o LU350.o LU351.o LU352.o LU353.o LU354.o LU355.o LU356.o LU357.o LU358.o LU359.o LU360.o LU361.o LU362.o LU363.o LU364.o LU365.o LU366.o LU367.o LU368.o LU369.o LU370.o LU371.o LU372.o LU373.o LU374.o LU375.o LU376.o LU377.o LU378.o LU379.o LU380.o LU381.o LU382.o LU383.o LU384.o LU385.o LU386.o LU387.o LU388.o LU389.o LU390.o LU391.o LU392.o LU393.o LU394.o LU395.o LU396.o LU397.o LU398.o LU399.o LU400.o LU401.o LU402.o LU403.o LU404.o LU405.o LU406.o LU407.o LU408.o LU409.o LU410.o LU411.o LU412.o LU413.o LU414.o LU415.o LU416.o LU417.o LU418.o LU419.o LU420.o LU421.o LU422.o LU423.o LU424.o LU425.o LU426.o LU427.o LU428.o LU429.o LU430.o LU431.o LU432.o LU433.o LU434.o LU435.o LU436.o LU437.o LU438.o LU439.o LU440.o LU441.o LU442.o LU443.o LU444.o LU445.o LU446.o LU447.o LU448.o LU449.o LU450.o LU451.o LU452.o LU453.o LU454.o LU455.o LU456.o LU457.o LU458.o LU459.o LU460.o LU461.o LU462.o LU463.o LU464.o LU465.o LU466.o LU467.o LU468.o LU469.o LU470.o LU471.o LU472.o LU473.o LU474.o LU475.o LU476.o LU477.o LU478.o LU479.o LU480.o LU481.o LU482.o LU483.o LU484.o LU485.o LU486.o LU487.o LU488.o LU489.o LU490.o LU491.o LU492.o LU493.o LU494.o LU495.o LU496.o LU497.o LU498.o LU499.o LU500.o LU501.o LU502.o LU503.o LU504.o LU505.o LU506.o LU507.o LU508.o LU509.o LU510.o LU511.o LU512.o LU513.o LU514.o LU515.o LU516.o LU517.o LU518.o LU519.o LU520.o LU521.o LU522.o LU523.o LU524.o LU525.o LU526.o LU527.o LU528.o LU529.o LU530.o LU531.o LU532.o LU533.o LU534.o LU535.o LU536.o LU537.o LU538.o LU539.o LU540.o LU541.o LU542.o LU543.o LU544.o LU545.o LU546.o LU547.o LU548.o LU549.o LU550.o LU551.o LU552.o LU553.o LU554.o LU555.o LU556.o LU557.o LU558.o LU559.o LU560.o LU561.o LU562.o LU563.o LU564.o LU565.o LU566.o LU567.o LU568.o LU569.o LU570.o LU571.o LU572.o LU573.o LU574.o LU575.o LU576.o LU577.o LU578.o LU579.o LU580.o LU581.o LU582.o LU583.o LU584.o LU585.o LU586.o LU587.o LU588.o LU589.o LU590.o LU591.o LU592.o LU593.o LU594.o LU595.o LU596.o LU597.o LU598.o LU599.o LU600.o LU601.o LU602.o LU603.o LU604.o LU605.o LU606.o LU607.o LU608.o LU609.o LU610.o LU611.o LU612.o LU613.o LU614.o LU615.o LU616.o LU617.o LU618.o LU619.o LU620.o LU621.o LU622.o LU623.o LU624.o LU625.o LU626.o LU627.o LU628.o LU629.o LU630.o LU631.o LU632.o LU633.o LU634.o LU635.o LU636.o LU637.o LU638.o LU639.o LU640.o LU641.o LU642.o LU643.o LU644.o LU645.o LU646.o LU647.o LU648.o LU649.o LU650.o LU651.o LU652.o LU653.o LU654.o LU655.o LU656.o LU657.o LU658.o LU659.o LU660.o LU661.o LU662.o LU663.o LU664.o LU665.o LU666.o LU667.o LU668.o LU669.o LU670.o LU671.o LU672.o LU673.o LU674.o LU675.o LU676.o LU677.o LU678.o LU679.o LU680.o LU681.o LU682.o LU683.o LU684.o LU685.o LU686.o LU687.o LU688.o LU689.o LU690.o LU691.o LU692.o LU693.o LU694.o LU695.o LU696.o LU697.o LU698.o LU699.o LU700.o LU701.o LU702.o LU703.o LU704.o LU705.o LU706.o LU707.o LU708.o LU709.o LU710.o LU711.o LU712.o LU713.o LU714.o LU715.o LU716.o LU717.o LU718.o LU719.o LU720.o LU721.o LU722.o LU723.o LU724.o LU725.o LU726.o LU727.o LU728.o LU729.o LU730.o LU731.o LU732.o LU733.o LU734.o LU735.o LU736.o LU737.o LU738.o LU739.o LU740.o LU741.o LU742.o LU743.o LU744.o LU745.o LU746.o LU747.o LU748.o LU749.o LU750.o LU751.o LU752.o LU753.o LU754.o LU755.o LU756.o LU757.o LU758.o LU759.o LU760.o LU761.o LU762.o LU763.o LU764.o LU765.o LU766.o LU767.o LU768.o LU769.o LU770.o LU771.o LU772.o LU773.o LU774.o LU775.o LU776.o LU777.o LU778.o LU779.o LU780.o LU781.o LU782.o LU783.o LU784.o LU785.o LU786.o LU787.o LU788.o LU789.o LU790.o LU791.o LU792.o LU793.o LU794.o LU795.o LU796.o LU797.o LU798.o LU799.o LU800.o LU801.o LU802.o LU803.o LU804.o LU805.o LU806.o LU807.o LU808.o LU809.o LU810.o LU811.o LU812.o LU813.o LU814.o LU815.o LU816.o LU817.o LU818.o LU819.o LU820.o LU821.o LU822.o LU823.o LU824.o LU825.o LU826.o LU827.o LU828.o LU829.o LU830.o LU831.o LU832.o LU833.o LU834.o LU835.o LU836.o LU837.o LU838.o LU839.o LU840.o LU841.o LU842.o LU843.o LU844.o LU845.o LU846.o LU847.o LU848.o LU849.o LU850.o LU851.o LU852.o LU853.o LU854.o LU855.o LU856.o LU857.o LU858.o LU859.o LU860.o LU861.o LU862.o LU863.o LU864.o LU865.o LU866.o LU867.o LU868.o LU869.o LU870.o LU871.o LU872.o LU873.o LU874.o LU875.o LU876.o LU877.o LU878.o LU879.o LU880.o LU881.o LU882.o LU883.o LU884.o LU885.o LU886.o LU887.o LU888.o LU889.o LU890.o LU891.o LU892.o LU893.o LU894.o LU895.o LU896.o LU897.o LU898.o LU899.o LU900.o LU901.o LU902.o LU903.o LU904.o LU905.o LU906.o LU907.o LU908.o LU909.o LU910.o LU911.o LU912.o LU913.o LU914.o LU915.o LU916.o LU917.o LU918.o LU919.o LU920.o LU921.o LU922.o LU923.o LU924.o LU925.o LU926.o LU927.o LU928.o LU929.o LU930.o LU931.o LU932.o LU933.o LU934.o LU935.o LU936.o LU937.o LU938.o LU939.o LU940.o LU941.o LU942.o LU943.o LU944.o LU945.o LU946.o LU947.o LU948.o LU949.o LU950.o LU951.o LU952.o LU953.o LU954.o LU955.o LU956.o LU957.o LU958.o LU959.o LU960.o LU961.o LU962.o LU963.o LU964.o LU965.o LU966.o LU967.o LU968.o LU969.o LU970.o LU971.o LU972.o LU973.o LU974.o LU975.o LU976.o LU977.o LU978.o LU979.o LU980.o LU981.o LU982.o LU983.o LU984.o LU985.o LU986.o LU987.o LU988.o LU989.o LU990.o LU991.o LU992.o LU993.o LU994.o LU995.o LU996.o LU997.o LU998.o LU999.o -o Scimark2.exe -L"C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/lib" -L"C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/x86_64-w64-mingw32/lib" -static-libgcc -mcmodel=large -fPIC -Wl,--image-base -Wl,0x10000000
C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o: in function `check_managed_app':
relocation truncated to fit: R_X86_64_PC32 against symbol `.refptr.mingw_initltsdrot_force' defined in .rdata$.refptr.mingw_initltsdrot_force[.refptr.mingw_initltsdrot_force] section in C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o
relocation truncated to fit: R_X86_64_PC32 against symbol `.refptr.mingw_initltsdyn_force' defined in .rdata$.refptr.mingw_initltsdyn_force[.refptr.mingw_initltsdyn_force] section in C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o
relocation truncated to fit: R_X86_64_PC32 against symbol `.refptr.mingw_initltssuo_force' defined in .rdata$.refptr.mingw_initltssuo_force[.refptr.mingw_initltssuo_force] section in C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o
relocation truncated to fit: R_X86_64_PC32 against symbol `.refptr.mingw_initcharmax' defined in .rdata$.refptr.mingw_initcharmax[.refptr.mingw_initcharmax] section in C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o
relocation truncated to fit: R_X86_64_PC32 against symbol `.refptr.__image_base__' defined in .rdata$.refptr.__image_base__[.refptr.__image_base__] section in C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o
C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o:
in function `pre_c_init':
relocation truncated to fit: R_X86_64_PC32 against symbol `.refptr.mingw_app_type' defined in .rdata$.refptr.mingw_app_type[.refptr.mingw_app_type] section in C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o
C:/crossdev/src/mingw-w64-v7-git20191109/mingw-w64-crt/crt/crtexe.c:140:(.text+0x70): relocation truncated to fit: R_X86_64_PC32 against `.bss'
C:/crossdev/src/mingw-w64-v7-git20191109/mingw-w64-crt/crt/crtexe.c:144:(.text+0x80): relocation truncated to fit: R_X86_64_PC32 against symbol `__set_app_type' defined in .text section in C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/x86_64-w64-mingw32/lib/libmsvcrt.a(dwngs00096.o)
C:/crossdev/src/mingw-w64-v7-git20191109/mingw-w64-crt/crt/crtexe.c:146:(.text+0x85): relocation truncated to fit: R_X86_64_PC32 against symbol `__p__fmode' defined in .text section in C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/x86_64-w64-mingw32/lib/libmsvcrt.a(lib64_libmsvcrt_os_a-__p__fmode.o)
C:/crossdev/src/mingw-w64-v7-git20191109/mingw-w64-crt/crt/crtexe.c:146:(.text+0x8c): relocation truncated to fit: R_X86_64_PC32 against symbol `.refptr._fmode' defined in .rdata$.refptr._fmode[.refptr._fmode] section in C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o
C:/crossdev/src/mingw-w64-v7-git20191109/mingw-w64-crt/crt/crtexe.c:152:(.text+0x95): additional relocation overflows omitted from the output
collect2.exe: error: ld returned 1 exit status
C:DScimark2-Dev-Cpp-masterMakefile.win:25: recipe for target 'Scimark2.exe' failed
mingw32-make.exe: *** [Scimark2.exe] Error 1
After so more testing it would appear that the 2GB executable size limit (regardless of using -mcmodel=medium or -mcmodel=large) is the roadblock the above error. I was able to do a 100 file 1,000,000 lines per file compile and it generated a ~1.1GB executable. I started using -Os (which optimizes for size) and that moved the project forward quite a bit. A couple things to note here is that the larger the executable the slower the Scimark2 score is which is interesting. The first successful 1 billion line compile using 1000 1,000,000 line files and -Os generated a 359MB executable in 1483 seconds (24.7 minutes). I also tried 500 files with 2,000,000 lines and that actually took longer. The default Scimark2 project is 4X faster than the project with the extra 1 billion lines of code when the executable is larger and when compiled with -Os.
I don’t feel like this compile time accurately represents the 3990x Threadripper because on the 1 million and 2 million lines of code file sizes all of the cores are not being used. I don’t know if this is an issue with MAKE and G++ or the automated -j setting where it selects the number of cores to use or even if there is an IO bottleneck on the machine it is not able to handle it. The smaller the files the more of the cores the MAKE/G++ -j combo uses. I’ve also tried it with and without the -pipe flag which uses pipes instead of files during the compilation. What is also interesting here is that TwineCompile in C++Builder doesn’t seem to have the same limitation. When using it to parallel compile all of the cores instantly fire up.
In an effort to get a faster compile time on 1 billion lines of C++ code I loaded up 4 instances of Dev-C++ with 250 1,000,000 lines of code files in the project and compiled all 4 projects at the same time. This is similar to the 1 billion lines of Object Pascal code because under that project it was compiling 250 projects with 4 million lines of code per project. And here we have the results of the quad compile.
- Errors: 0
- Warnings: 0
- Output Filename: C:DScimark2-Dev-Cpp-master_250_1m_DScimark2.exe
- Output Size: 90.0009765625 MiB
- Compilation Time: 906.58s
- Errors: 0
- Warnings: 0
- Output Filename: C:DScimark2-Dev-Cpp-master_250_1m_CScimark2.exe
- Output Size: 90.0009765625 MiB
- Compilation Time: 909.45s
- Errors: 0
- Warnings: 0
- Output Filename: C:DScimark2-Dev-Cpp-master_250_1m_AScimark2.exe
- Output Size: 90.0009765625 MiB
- Compilation Time: 915.17s
- Errors: 0
- Warnings: 0
- Output Filename: C:DScimark2-Dev-Cpp-master_250_1m_BScimark2.exe
- Output Size: 90.0009765625 MiB
- Compilation Time: 918.05s
1 billion lines of C++ code in 15 minutes on the AMD 3990X Threadripper.
This project was a lot of fun and there are all kinds of different C++ flags for the TDM-GCC compiler like -mtune=native, -mtune=znver2, and -mtune=znver3 which I haven’t tried with this setup. As we’ve seen in this post the software support for a modern machine with 64 cores and 128 threads is still getting all the kinks worked out but generally works and delivers some serious computing power. C++Builder with TwineCompile is a powerful productivity solution for multi-core machines compiling 1 million lines of code very quickly and can work better than the MAKE/GCC parallel compilation Jobs feature due to it’s deep IDE integration. The open source Dev-C++ is a pretty powerful solution when working with large code bases and large files and could take more advantage of the Parallel Programming Library in Delphi. I was impressed by how responsive the Dev-C++ UI is during the parallel compilation. Ready to get started building Windows apps in C++? Try out C++Builder or Dev-C++ from the links below. You can also investigate more about learning C++ and other modern hardware articles featuring the 5950X 16 core machine below.