1 /* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "DMJsonWriter.h" 9 10 #include "ProcStats.h" 11 #include "SkCommonFlags.h" 12 #include "SkData.h" 13 #include "SkJSON.h" 14 #include "SkJSONWriter.h" 15 #include "SkMutex.h" 16 #include "SkOSFile.h" 17 #include "SkOSPath.h" 18 #include "SkStream.h" 19 #include "SkTArray.h" 20 21 namespace DM { 22 23 SkTArray<JsonWriter::BitmapResult> gBitmapResults; 24 SK_DECLARE_STATIC_MUTEX(gBitmapResultLock); 25 26 void JsonWriter::AddBitmapResult(const BitmapResult& result) { 27 SkAutoMutexAcquire lock(&gBitmapResultLock); 28 gBitmapResults.push_back(result); 29 } 30 31 SkTArray<skiatest::Failure> gFailures; 32 SK_DECLARE_STATIC_MUTEX(gFailureLock); 33 34 void JsonWriter::AddTestFailure(const skiatest::Failure& failure) { 35 SkAutoMutexAcquire lock(gFailureLock); 36 gFailures.push_back(failure); 37 } 38 39 void JsonWriter::DumpJson() { 40 if (FLAGS_writePath.isEmpty()) { 41 return; 42 } 43 44 SkString path = SkOSPath::Join(FLAGS_writePath[0], "dm.json"); 45 sk_mkdir(FLAGS_writePath[0]); 46 SkFILEWStream stream(path.c_str()); 47 SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty); 48 49 writer.beginObject(); // root 50 51 for (int i = 1; i < FLAGS_properties.count(); i += 2) { 52 writer.appendString(FLAGS_properties[i-1], FLAGS_properties[i]); 53 } 54 55 writer.beginObject("key"); 56 for (int i = 1; i < FLAGS_key.count(); i += 2) { 57 writer.appendString(FLAGS_key[i-1], FLAGS_key[i]); 58 } 59 writer.endObject(); 60 61 int maxResidentSetSizeMB = sk_tools::getMaxResidentSetSizeMB(); 62 if (maxResidentSetSizeMB != -1) { 63 writer.appendS32("max_rss_MB", maxResidentSetSizeMB); 64 } 65 66 { 67 SkAutoMutexAcquire lock(&gBitmapResultLock); 68 writer.beginArray("results"); 69 for (int i = 0; i < gBitmapResults.count(); i++) { 70 writer.beginObject(); 71 72 writer.beginObject("key"); 73 writer.appendString("name" , gBitmapResults[i].name.c_str()); 74 writer.appendString("config" , gBitmapResults[i].config.c_str()); 75 writer.appendString("source_type", gBitmapResults[i].sourceType.c_str()); 76 77 // Source options only need to be part of the key if they exist. 78 // Source type by source type, we either always set options or never set options. 79 if (!gBitmapResults[i].sourceOptions.isEmpty()) { 80 writer.appendString("source_options", gBitmapResults[i].sourceOptions.c_str()); 81 } 82 writer.endObject(); // key 83 84 writer.beginObject("options"); 85 writer.appendString("ext" , gBitmapResults[i].ext.c_str()); 86 writer.appendString("gamma_correct", gBitmapResults[i].gammaCorrect ? "yes" : "no"); 87 writer.endObject(); // options 88 89 writer.appendString("md5", gBitmapResults[i].md5.c_str()); 90 91 writer.endObject(); // 1 result 92 } 93 writer.endArray(); // results 94 } 95 96 { 97 SkAutoMutexAcquire lock(gFailureLock); 98 if (gFailures.count() > 0) { 99 writer.beginObject("test_results"); 100 writer.beginArray("failures"); 101 for (int i = 0; i < gFailures.count(); i++) { 102 writer.beginObject(); 103 writer.appendString("file_name", gFailures[i].fileName); 104 writer.appendS32 ("line_no" , gFailures[i].lineNo); 105 writer.appendString("condition", gFailures[i].condition); 106 writer.appendString("message" , gFailures[i].message.c_str()); 107 writer.endObject(); // 1 failure 108 } 109 writer.endArray(); // failures 110 writer.endObject(); // test_results 111 } 112 } 113 114 writer.endObject(); // root 115 writer.flush(); 116 stream.flush(); 117 } 118 119 using namespace skjson; 120 121 bool JsonWriter::ReadJson(const char* path, void(*callback)(BitmapResult)) { 122 sk_sp<SkData> json(SkData::MakeFromFileName(path)); 123 if (!json) { 124 return false; 125 } 126 127 DOM dom((const char*)json->data(), json->size()); 128 const ObjectValue* root = dom.root(); 129 if (!root) { 130 return false; 131 } 132 133 const ArrayValue* results = (*root)["results"]; 134 if (!results) { 135 return false; 136 } 137 138 BitmapResult br; 139 for (const ObjectValue* r : *results) { 140 const ObjectValue& key = (*r)["key"].as<ObjectValue>(); 141 const ObjectValue& options = (*r)["options"].as<ObjectValue>(); 142 143 br.name = key["name"].as<StringValue>().begin(); 144 br.config = key["config"].as<StringValue>().begin(); 145 br.sourceType = key["source_type"].as<StringValue>().begin(); 146 br.ext = options["ext"].as<StringValue>().begin(); 147 br.gammaCorrect = 0 == strcmp("yes", options["gamma_correct"].as<StringValue>().begin()); 148 br.md5 = (*r)["md5"].as<StringValue>().begin(); 149 150 if (const StringValue* so = key["source_options"]) { 151 br.sourceOptions = so->begin(); 152 } 153 callback(br); 154 } 155 return true; 156 } 157 158 } // namespace DM 159