@@ -380,27 +380,73 @@ defmodule Kernel.ParallelCompiler do
380380 end
381381 end
382382
383- defp write_module_binaries ( result , { :compile , path } , timestamp ) do
384- File . mkdir_p! ( path )
385- Code . prepend_path ( path )
386-
387- for { { :module , module } , { binary , _ } } when is_binary ( binary ) <- result do
388- full_path = Path . join ( path , Atom . to_string ( module ) <> ".beam" )
389- File . write! ( full_path , binary )
390- if timestamp , do: File . touch! ( full_path , timestamp )
391- module
392- end
383+ defp write_module_binaries ( result , { :compile , path } , state ) when map_size ( result ) > 0 do
384+ profile ( state , "writing modules to disk" , fn ->
385+ File . mkdir_p! ( path )
386+ Code . prepend_path ( path )
387+ timestamp = state . beam_timestamp
388+
389+ # We fan-out the writes as that improves performance
390+ # when writing hundreds of beam files. This is cheap as
391+ # we only transfer atoms and binaries across processes.
392+ pool_size = min ( map_size ( result ) , state . schedulers )
393+
394+ pool_list =
395+ for _ <- 1 .. pool_size do
396+ spawn_link ( fn -> write_loop ( path , timestamp ) end )
397+ end
398+
399+ pool_tuple = List . to_tuple ( pool_list )
400+
401+ { modules , _ } =
402+ Enum . flat_map_reduce ( result , 0 , fn
403+ { { :module , module } , { binary , _ } } , scheduler when is_binary ( binary ) ->
404+ send ( elem ( pool_tuple , scheduler ) , { :write , module , binary } )
405+ { [ module ] , rem ( scheduler + 1 , pool_size ) }
406+
407+ _ , scheduler ->
408+ { [ ] , scheduler }
409+ end )
410+
411+ pool_refs =
412+ for pid <- pool_list do
413+ ref = Process . monitor ( pid )
414+ send ( pid , :done )
415+ ref
416+ end
417+
418+ for ref <- pool_refs do
419+ receive do
420+ { :DOWN , ^ ref , _ , _ , _ } -> :ok
421+ end
422+ end
423+
424+ modules
425+ end )
393426 end
394427
395- defp write_module_binaries ( result , _output , _timestamp ) do
428+ defp write_module_binaries ( result , _output , _state ) do
396429 for { { :module , module } , { binary , _ } } when is_binary ( binary ) <- result , do: module
397430 end
398431
432+ defp write_loop ( path , timestamp ) do
433+ receive do
434+ { :write , module , binary } ->
435+ full_path = Path . join ( path , Atom . to_string ( module ) <> ".beam" )
436+ File . write! ( full_path , binary , [ :raw ] )
437+ if timestamp , do: File . touch! ( full_path , timestamp )
438+ write_loop ( path , timestamp )
439+
440+ :done ->
441+ :ok
442+ end
443+ end
444+
399445 ## Verification
400446
401447 defp verify_modules ( result , compile_warnings , dependent_modules , state ) do
402- modules = write_module_binaries ( result , state . output , state . beam_timestamp )
403- _ = state . after_compile . ( )
448+ modules = write_module_binaries ( result , state . output , state )
449+ profile ( state , "after compile callback" , state . after_compile )
404450
405451 runtime_warnings =
406452 if state . verification? do
0 commit comments