@@ -34,6 +34,7 @@ TRACELOGGING_DEFINE_PROVIDER(g_hEtwProvider,
3434 (0xca13db84 , 0xd0a9 , 0x5145 , 0xfc , 0xa4 , 0x46 , 0x8d , 0xa9 , 0x2f , 0xdc , 0x2d ));
3535
3636SystemInformation g_SystemInformation;
37+ ULONG g_ExperimentFlags;
3738
3839UINT64 PerfTimer::GetTime ()
3940{
@@ -99,12 +100,12 @@ UINT64 PerfTimer::SecondsToPerfTime(const double seconds)
99100Random::Random (UINT64 ulSeed)
100101{
101102 UINT32 i;
102-
103+
103104 _ulState[0 ] = 0xf1ea5eed ;
104105 _ulState[1 ] = ulSeed;
105106 _ulState[2 ] = ulSeed;
106107 _ulState[3 ] = ulSeed;
107-
108+
108109 for (i = 0 ; i < 20 ; i++) {
109110 Rand64 ();
110111 }
@@ -138,10 +139,10 @@ void Random::RandBuffer(BYTE *pBuffer, UINT32 ulLength, bool fPseudoRandomOkay)
138139 pBuffer += Remaining * 8 ;
139140
140141 if (fPseudoRandomOkay ) {
141-
142+
142143 //
143144 // Generate 5 random numbers and then mix them to produce
144- // 16 random (but correlated) numbers. We want to do 16
145+ // 16 random (but correlated) numbers. We want to do 16
145146 // numbers at a time for optimal cache line alignment.
146147 // Only do this if the caller is okay with numbers that
147148 // aren't independent. A detailed analysis of the data
@@ -150,7 +151,7 @@ void Random::RandBuffer(BYTE *pBuffer, UINT32 ulLength, bool fPseudoRandomOkay)
150151 // instance it's unlikely compression algorithms will be
151152 // able to detect this and utilize it).
152153 //
153-
154+
154155 while (Remaining > 16 ) {
155156 r1 = Rand64 ();
156157 r2 = Rand64 ();
@@ -195,7 +196,7 @@ void Random::RandBuffer(BYTE *pBuffer, UINT32 ulLength, bool fPseudoRandomOkay)
195196 //
196197 // Fill in the tail of the buffer
197198 //
198-
199+
199200 while (Remaining >= 4 ) {
200201 r1 = Rand64 ();
201202 r2 = Rand64 ();
@@ -241,7 +242,7 @@ string ThreadTarget::GetXml(UINT32 indent) const
241242{
242243 char buffer[4096 ];
243244 string sXml ;
244-
245+
245246 AddXmlInc (sXml , " <ThreadTarget>\n " );
246247
247248 sprintf_s (buffer, _countof (buffer), " <Thread>%u</Thread>\n " , _ulThread);
@@ -262,7 +263,7 @@ string Target::GetXml(UINT32 indent) const
262263{
263264 char buffer[4096 ];
264265 string sXml ;
265-
266+
266267 AddXmlInc (sXml , " <Target>\n " );
267268 AddXml (sXml , " <Path>" + _sPath + " </Path>\n " );
268269
@@ -295,7 +296,7 @@ string Target::GetXml(UINT32 indent) const
295296 AddXml (sXml , " <WriteThrough>true</WriteThrough>\n " );
296297 break ;
297298 }
298-
299+
299300 // MemoryMappedIoMode::Off is implied default
300301 switch (_memoryMappedIoMode)
301302 {
@@ -416,7 +417,7 @@ string Target::GetXml(UINT32 indent) const
416417 {
417418 sprintf_s (buffer, _countof (buffer), " <StrideSize>%I64u</StrideSize>\n " , GetBlockAlignmentInBytes ());
418419 AddXml (sXml , buffer);
419-
420+
420421 AddXml (sXml , _fInterlockedSequential ?
421422 " <InterlockedSequential>true</InterlockedSequential>\n " :
422423 " <InterlockedSequential>false</InterlockedSequential>\n " );
@@ -672,6 +673,13 @@ string Profile::GetXml(UINT32 indent) const
672673 sprintf_s (buffer, _countof (buffer), " <Progress>%u</Progress>\n " , _dwProgress);
673674 AddXml (sXml , buffer);
674675
676+ if (g_ExperimentFlags)
677+ {
678+ // only output if on so that downlevel doesn't get (and fail: not in downlevel xsd) unless actually specified
679+ sprintf_s (buffer, _countof (buffer), " <ExperimentFlags>%u</ExperimentFlags>\n " , g_ExperimentFlags);
680+ AddXml (sXml , buffer);
681+ }
682+
675683 if (_resultsFormat == ResultsFormat::Text)
676684 {
677685 AddXml (sXml , " <ResultFormat>text</ResultFormat>\n " );
@@ -686,6 +694,12 @@ string Profile::GetXml(UINT32 indent) const
686694 }
687695
688696 AddXml (sXml , _fVerbose ? " <Verbose>true</Verbose>\n " : " <Verbose>false</Verbose>\n " );
697+ if (_fVerboseStats)
698+ {
699+ // only output if on so that downlevel doesn't get (and fail: not in downlevel xsd) unless actually specified
700+ AddXml (sXml , " <VerboseStats>true</VerboseStats>\n " );
701+ }
702+
689703 if (_precreateFiles == PrecreateFiles::UseMaxSize)
690704 {
691705 AddXml (sXml , " <PrecreateFiles>UseMaxSize</PrecreateFiles>\n " );
@@ -763,7 +777,7 @@ bool Profile::Validate(bool fSingleSpec, SystemInformation *pSystem) const
763777 }
764778 if (fOk && !pSystem->processorTopology ._vProcessorGroupInformation [Affinity.wGroup ].IsProcessorValid (Affinity.bProc ))
765779 {
766- fprintf (stderr, " ERROR: affinity assignment to group %u core %u not possible; group only has %u cores \n " ,
780+ fprintf (stderr, " ERROR: affinity assignment to group %u cpu %u not possible; group has a max of %u cpus \n " ,
767781 Affinity.wGroup ,
768782 Affinity.bProc ,
769783 pSystem->processorTopology ._vProcessorGroupInformation [Affinity.wGroup ]._maximumProcessorCount );
@@ -773,22 +787,27 @@ bool Profile::Validate(bool fSingleSpec, SystemInformation *pSystem) const
773787
774788 if (fOk && !pSystem->processorTopology ._vProcessorGroupInformation [Affinity.wGroup ].IsProcessorActive (Affinity.bProc ))
775789 {
776- fprintf (stderr, " ERROR: affinity assignment to group %u core %u not possible; core is not active (current mask 0x%Ix )\n " ,
790+ fprintf (stderr, " ERROR: affinity assignment to group %u cpu %u not possible; cpu is not active (current mask 0x%p )\n " ,
777791 Affinity.wGroup ,
778792 Affinity.bProc ,
779- pSystem->processorTopology ._vProcessorGroupInformation [Affinity.wGroup ]._activeProcessorMask );
793+ ( void *) pSystem->processorTopology ._vProcessorGroupInformation [Affinity.wGroup ]._activeProcessorMask );
780794
781795 fOk = false ;
782796 }
783797 }
784798 }
785799
800+ // ISSUE: many of the following validation errors are stated in cmdline terms, which is not helpful for XML
801+
786802 if (timeSpan.GetDisableAffinity () && timeSpan.GetAffinityAssignments ().size () > 0 )
787803 {
788804 fprintf (stderr, " ERROR: -n and -a parameters cannot be used together\n " );
789805 fOk = false ;
790806 }
791807
808+ // ISSUE: with XML and the following the target specification validation it would be useful to say what
809+ // target they're for
810+
792811 for (const auto & target : timeSpan.GetTargets ())
793812 {
794813 const bool targetHasMultipleThreads = (timeSpan.GetThreadCount () > 1 ) || (target.GetThreadsPerFile () > 1 );
@@ -881,7 +900,7 @@ bool Profile::Validate(bool fSingleSpec, SystemInformation *pSystem) const
881900 fprintf (stderr, " ERROR: random distribution ranges (-rd) do not apply to sequential-only IO patterns\n " );
882901 fOk = false ;
883902 }
884-
903+
885904 if (target.GetUseParallelAsyncIO () && target.GetRequestCount () == 1 )
886905 {
887906 fprintf (stderr, " WARNING: -p does not have effect unless outstanding I/O count (-o) is > 1\n " );
@@ -958,7 +977,7 @@ bool Profile::Validate(bool fSingleSpec, SystemInformation *pSystem) const
958977 // Note that absolute range needs no additional validation - known nonzero/large enough for IO
959978 if (target.GetDistributionType () == DistributionType::Percent)
960979 {
961- if (targetAcc + r._dst .second > 100 )
980+ if (targetAcc + r._dst .second > 100 )
962981 {
963982 fprintf (stderr, " ERROR: invalid random distribution Target%% %I64u: can be at most %I64u - total must be <= 100%%\n " , r._dst .second , 100 - targetAcc);
964983 fOk = false ;
@@ -1036,10 +1055,20 @@ bool Profile::Validate(bool fSingleSpec, SystemInformation *pSystem) const
10361055 }
10371056 }
10381057
1039- // in the cases where there is only a single configuration specified for each target (e.g., cmdline),
1040- // currently there are no validations specific to individual targets (e.g., pre-existing files)
1041- // so we can stop validation now. this allows us to only warn/error once, as opposed to repeating
1042- // it for each target.
1058+ // Note that this error is only possible with -f or XML. The -Bbase:length form is immune.
1059+ if (target.GetMaxFileSize () && target.GetMaxFileSize () <= target.GetBaseFileOffsetInBytes ())
1060+ {
1061+ fprintf (stderr, " ERROR: maximum (-f) target offset must be greater than base (-B)\n " );
1062+ fOk = false ;
1063+ }
1064+
1065+ // If we know there is only a single target specification (the parameters which apply to targets) shared
1066+ // across the one or more targets, we can stop. In practical terms this is the command line case - for
1067+ // XML we don't know, and do need to keep going. This early exit lets us avoid repeating the same sets
1068+ // of error messages per each target we would otherwise loop over.
1069+ //
1070+ // If we ever did target property validation (say, v. its size) we'd want to divide out the validations
1071+ // into parameter-only v. parameter/property cases for similar reasons.
10431072 if (fSingleSpec )
10441073 {
10451074 break ;
@@ -1113,7 +1142,7 @@ BYTE* ThreadParameters::GetReadBuffer(size_t iTarget, size_t iRequest)
11131142BYTE* ThreadParameters::GetWriteBuffer (size_t iTarget, size_t iRequest)
11141143{
11151144 BYTE *pBuffer = nullptr ;
1116-
1145+
11171146 Target& target (vTargets[iTarget]);
11181147 size_t cb = static_cast <size_t >(target.GetRandomDataWriteBufferSize ());
11191148 if (cb == 0 )
0 commit comments