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 "SkJSONCPP.h"
14#include "SkMutex.h"
15#include "SkOSFile.h"
16#include "SkStream.h"
17#include "SkTArray.h"
18
19namespace DM {
20
21SkTArray<JsonWriter::BitmapResult> gBitmapResults;
22SK_DECLARE_STATIC_MUTEX(gBitmapResultLock);
23
24void JsonWriter::AddBitmapResult(const BitmapResult& result) {
25    SkAutoMutexAcquire lock(&gBitmapResultLock);
26    gBitmapResults.push_back(result);
27}
28
29SkTArray<skiatest::Failure> gFailures;
30SK_DECLARE_STATIC_MUTEX(gFailureLock);
31
32void JsonWriter::AddTestFailure(const skiatest::Failure& failure) {
33    SkAutoMutexAcquire lock(gFailureLock);
34    gFailures.push_back(failure);
35}
36
37void JsonWriter::DumpJson() {
38    if (FLAGS_writePath.isEmpty()) {
39        return;
40    }
41
42    Json::Value root;
43
44    for (int i = 1; i < FLAGS_properties.count(); i += 2) {
45        root[FLAGS_properties[i-1]] = FLAGS_properties[i];
46    }
47    for (int i = 1; i < FLAGS_key.count(); i += 2) {
48        root["key"][FLAGS_key[i-1]] = FLAGS_key[i];
49    }
50
51    {
52        SkAutoMutexAcquire lock(&gBitmapResultLock);
53        for (int i = 0; i < gBitmapResults.count(); i++) {
54            Json::Value result;
55            result["key"]["name"]        = gBitmapResults[i].name.c_str();
56            result["key"]["config"]      = gBitmapResults[i].config.c_str();
57            result["key"]["source_type"] = gBitmapResults[i].sourceType.c_str();
58            result["options"]["ext"]     = gBitmapResults[i].ext.c_str();
59            result["md5"]                = gBitmapResults[i].md5.c_str();
60
61            // Source options only need to be part of the key if they exist.
62            // Source type by source type, we either always set options or never set options.
63            if (!gBitmapResults[i].sourceOptions.isEmpty()) {
64                result["key"]["source_options"] = gBitmapResults[i].sourceOptions.c_str();
65            }
66
67            root["results"].append(result);
68        }
69    }
70
71    {
72        SkAutoMutexAcquire lock(gFailureLock);
73        for (int i = 0; i < gFailures.count(); i++) {
74            Json::Value result;
75            result["file_name"]     = gFailures[i].fileName;
76            result["line_no"]       = gFailures[i].lineNo;
77            result["condition"]     = gFailures[i].condition;
78            result["message"]       = gFailures[i].message.c_str();
79
80            root["test_results"]["failures"].append(result);
81        }
82    }
83
84    int maxResidentSetSizeMB = sk_tools::getMaxResidentSetSizeMB();
85    if (maxResidentSetSizeMB != -1) {
86        root["max_rss_MB"] = sk_tools::getMaxResidentSetSizeMB();
87    }
88
89    SkString path = SkOSPath::Join(FLAGS_writePath[0], "dm.json");
90    sk_mkdir(FLAGS_writePath[0]);
91    SkFILEWStream stream(path.c_str());
92    stream.writeText(Json::StyledWriter().write(root).c_str());
93    stream.flush();
94}
95
96bool JsonWriter::ReadJson(const char* path, void(*callback)(BitmapResult)) {
97    SkAutoTUnref<SkData> json(SkData::NewFromFileName(path));
98    if (!json) {
99        return false;
100    }
101
102    Json::Reader reader;
103    Json::Value root;
104    const char* data = (const char*)json->data();
105    if (!reader.parse(data, data+json->size(), root)) {
106        return false;
107    }
108
109    const Json::Value& results = root["results"];
110    BitmapResult br;
111    for (unsigned i = 0; i < results.size(); i++) {
112        const Json::Value& r = results[i];
113        br.name       = r["key"]["name"].asCString();
114        br.config     = r["key"]["config"].asCString();
115        br.sourceType = r["key"]["source_type"].asCString();
116        br.ext        = r["options"]["ext"].asCString();
117        br.md5        = r["md5"].asCString();
118
119        if (!r["key"]["source_options"].isNull()) {
120            br.sourceOptions = r["key"]["source_options"].asCString();
121        }
122        callback(br);
123    }
124    return true;
125}
126
127} // namespace DM
128