internal byte[] ParseDebuggerOutputText()
        {
            var byteOffset = (_command.ByteOffset % 4 == 0) ? _command.ByteOffset : _command.ByteOffset - (4 - _command.ByteOffset % 4);
            var lineOffset = _command.OutputOffset + (byteOffset / 4);
            var lineCount  = _command.ByteCount / 4;

            var dataDwords = TextDebuggerOutputParser.ReadTextOutput(_filePath, lineOffset, lineCount);
            var dataBytes  = new byte[dataDwords.Count * 4];

            Buffer.BlockCopy(dataDwords.ToArray(), 0, dataBytes, 0, dataBytes.Length);

            return(dataBytes);
        }
Esempio n. 2
0
        private async Task <(StepResult, BreakState)> DoReadDebugDataAsync(ReadDebugDataStep step)
        {
            var watches = _debugWatches;
            BreakStateDispatchParameters dispatchParams = null;

            if (!string.IsNullOrEmpty(step.WatchesFile.Path))
            {
                var result = await ReadDebugDataFileAsync("Valid watches", step.WatchesFile.Path, step.WatchesFile.IsRemote(), step.WatchesFile.CheckTimestamp);

                if (!result.TryGetResult(out var data, out var error))
                {
                    return(new StepResult(false, error.Message, ""), null);
                }

                var watchString = Encoding.UTF8.GetString(data);
                var watchArray  = watchString.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);

                watches = Array.AsReadOnly(watchArray);
            }
            if (!string.IsNullOrEmpty(step.DispatchParamsFile.Path))
            {
                var result = await ReadDebugDataFileAsync("Dispatch parameters", step.DispatchParamsFile.Path, step.DispatchParamsFile.IsRemote(), step.DispatchParamsFile.CheckTimestamp);

                if (!result.TryGetResult(out var data, out var error))
                {
                    return(new StepResult(false, error.Message, ""), null);
                }

                var paramsString         = Encoding.UTF8.GetString(data);
                var dispatchParamsResult = BreakStateDispatchParameters.Parse(paramsString);
                if (!dispatchParamsResult.TryGetResult(out dispatchParams, out error))
                {
                    return(new StepResult(false, error.Message, ""), null);
                }
            }
            {
                var outputPath          = step.OutputFile.Path;
                var initOutputTimestamp = GetInitialFileTimestamp(outputPath);

                int GetDispatchDwordCount(int fileDwordCount, out string warning)
                {
                    warning = "";
                    if (dispatchParams == null)
                    {
                        return(fileDwordCount);
                    }

                    var laneDataSize       = 1 /* system watch */ + watches.Count;
                    var totalLaneCount     = dispatchParams.GridSizeX * dispatchParams.GridSizeY * dispatchParams.GridSizeZ;
                    var dispatchDwordCount = (int)totalLaneCount * laneDataSize;

                    if (fileDwordCount < dispatchDwordCount)
                    {
                        warning = $"Output file ({outputPath}) is smaller than expected.\r\n\r\n" +
                                  $"Grid size as specified in the dispatch parameters file is ({dispatchParams.GridSizeX}, {dispatchParams.GridSizeY}, {dispatchParams.GridSizeZ}), " +
                                  $"which corresponds to {totalLaneCount} lanes. With {laneDataSize} DWORDs per lane, the output file is expected to contain at least " +
                                  $"{dispatchDwordCount} DWORDs, but it only contains {fileDwordCount} DWORDs.";
                    }

                    return(Math.Min(dispatchDwordCount, fileDwordCount));
                }

                BreakStateOutputFile outputFile;
                uint[] localOutputData = null;
                string stepWarning;

                if (step.OutputFile.IsRemote())
                {
                    var response = await _channel.SendWithReplyAsync <MetadataFetched>(
                        new FetchMetadata { FilePath = new[] { outputPath }, BinaryOutput = step.BinaryOutput }, _controller.CancellationToken);

                    if (response.Status == FetchStatus.FileNotFound)
                    {
                        return(new StepResult(false, $"Output file ({outputPath}) could not be found.", ""), null);
                    }
                    if (step.OutputFile.CheckTimestamp && response.Timestamp == initOutputTimestamp)
                    {
                        return(new StepResult(false, $"Output file ({outputPath}) was not modified. Data may be stale.", ""), null);
                    }

                    var offset             = step.BinaryOutput ? step.OutputOffset : step.OutputOffset * 4;
                    var fileByteCount      = Math.Max(0, response.ByteCount - offset);
                    var dispatchDwordCount = GetDispatchDwordCount(fileDwordCount: fileByteCount / 4, out stepWarning);
                    outputFile = new BreakStateOutputFile(outputPath, step.BinaryOutput, step.OutputOffset, response.Timestamp, dispatchDwordCount);
                }
                else
                {
                    var timestamp = GetLocalFileLastWriteTimeUtc(outputPath);
                    if (step.OutputFile.CheckTimestamp && timestamp == initOutputTimestamp)
                    {
                        return(new StepResult(false, $"Output file ({outputPath}) was not modified. Data may be stale.", ""), null);
                    }

                    int dispatchDwordCount;
                    if (step.BinaryOutput)
                    {
                        if (!ReadLocalFile(outputPath, out var outputBytes, out var readError))
                        {
                            return(new StepResult(false, "Output file could not be opened. " + readError, ""), null);
                        }

                        var fileByteCount = Math.Max(0, outputBytes.Length - step.OutputOffset);
                        dispatchDwordCount = GetDispatchDwordCount(fileDwordCount: fileByteCount / 4, out stepWarning);
                        localOutputData    = new uint[dispatchDwordCount];
                        Buffer.BlockCopy(outputBytes, step.OutputOffset, localOutputData, 0, dispatchDwordCount * 4);
                    }
                    else
                    {
                        var outputDwords = TextDebuggerOutputParser.ReadTextOutput(outputPath, step.OutputOffset);

                        dispatchDwordCount = GetDispatchDwordCount(fileDwordCount: outputDwords.Count, out stepWarning);
                        if (outputDwords.Count > dispatchDwordCount)
                        {
                            outputDwords.RemoveRange(dispatchDwordCount, outputDwords.Count - dispatchDwordCount);
                        }
                        localOutputData = outputDwords.ToArray();
                    }

                    outputFile = new BreakStateOutputFile(outputPath, step.BinaryOutput, offset: 0, timestamp, dispatchDwordCount);
                }

                var data = new BreakStateData(watches, outputFile, localOutputData);
                return(new StepResult(true, stepWarning, ""), new BreakState(data, dispatchParams));
            }
        }