1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 ==============================================================================*/ 15 16 #include "tensorflow/core/util/events_writer.h" 17 18 #include <math.h> 19 #include "tensorflow/core/framework/summary.pb.h" 20 #include "tensorflow/core/lib/core/errors.h" 21 #include "tensorflow/core/lib/core/status.h" 22 #include "tensorflow/core/lib/core/status_test_util.h" 23 #include "tensorflow/core/lib/io/path.h" 24 #include "tensorflow/core/lib/io/record_reader.h" 25 #include "tensorflow/core/lib/strings/strcat.h" 26 #include "tensorflow/core/platform/env.h" 27 #include "tensorflow/core/platform/logging.h" 28 #include "tensorflow/core/platform/protobuf.h" 29 #include "tensorflow/core/platform/test.h" 30 #include "tensorflow/core/util/event.pb.h" 31 32 namespace tensorflow { 33 namespace { 34 35 // shorthand 36 Env* env() { return Env::Default(); } 37 38 void WriteSimpleValue(EventsWriter* writer, double wall_time, int64 step, 39 const string& tag, float simple_value) { 40 Event event; 41 event.set_wall_time(wall_time); 42 event.set_step(step); 43 Summary::Value* summ_val = event.mutable_summary()->add_value(); 44 summ_val->set_tag(tag); 45 summ_val->set_simple_value(simple_value); 46 writer->WriteEvent(event); 47 } 48 49 void WriteFile(EventsWriter* writer) { 50 WriteSimpleValue(writer, 1234, 34, "foo", 3.14159); 51 WriteSimpleValue(writer, 2345, 35, "bar", -42); 52 } 53 54 static bool ReadEventProto(io::RecordReader* reader, uint64* offset, 55 Event* proto) { 56 string record; 57 Status s = reader->ReadRecord(offset, &record); 58 if (!s.ok()) { 59 return false; 60 } 61 return ParseProtoUnlimited(proto, record); 62 } 63 64 void VerifyFile(const string& filename) { 65 CHECK(env()->FileExists(filename).ok()); 66 std::unique_ptr<RandomAccessFile> event_file; 67 TF_CHECK_OK(env()->NewRandomAccessFile(filename, &event_file)); 68 io::RecordReader* reader = new io::RecordReader(event_file.get()); 69 70 uint64 offset = 0; 71 72 Event actual; 73 CHECK(ReadEventProto(reader, &offset, &actual)); 74 VLOG(1) << actual.ShortDebugString(); 75 // Wall time should be within 5s of now. 76 77 double current_time = env()->NowMicros() / 1000000.0; 78 EXPECT_LT(fabs(actual.wall_time() - current_time), 5); 79 // Should have the current version number. 80 EXPECT_EQ(actual.file_version(), 81 strings::StrCat(EventsWriter::kVersionPrefix, 82 EventsWriter::kCurrentVersion)); 83 84 Event expected; 85 CHECK(ReadEventProto(reader, &offset, &actual)); 86 VLOG(1) << actual.ShortDebugString(); 87 ASSERT_TRUE(protobuf::TextFormat::ParseFromString( 88 "wall_time: 1234 step: 34 " 89 "summary { value { tag: 'foo' simple_value: 3.14159 } }", 90 &expected)); 91 // TODO(keveman): Enable this check 92 // EXPECT_THAT(expected, EqualsProto(actual)); 93 94 CHECK(ReadEventProto(reader, &offset, &actual)); 95 VLOG(1) << actual.ShortDebugString(); 96 ASSERT_TRUE(protobuf::TextFormat::ParseFromString( 97 "wall_time: 2345 step: 35 " 98 "summary { value { tag: 'bar' simple_value: -42 } }", 99 &expected)); 100 // TODO(keveman): Enable this check 101 // EXPECT_THAT(expected, EqualsProto(actual)); 102 103 TF_CHECK_OK(env()->DeleteFile(filename)); 104 delete reader; 105 } 106 107 string GetDirName(const string& suffix) { 108 return io::JoinPath(testing::TmpDir(), suffix); 109 } 110 111 TEST(EventWriter, WriteFlush) { 112 string file_prefix = GetDirName("/writeflush_test"); 113 EventsWriter writer(file_prefix); 114 WriteFile(&writer); 115 TF_EXPECT_OK(writer.Flush()); 116 string filename = writer.FileName(); 117 VerifyFile(filename); 118 } 119 120 TEST(EventWriter, WriteClose) { 121 string file_prefix = GetDirName("/writeclose_test"); 122 EventsWriter writer(file_prefix); 123 WriteFile(&writer); 124 TF_EXPECT_OK(writer.Close()); 125 string filename = writer.FileName(); 126 VerifyFile(filename); 127 } 128 129 TEST(EventWriter, WriteDelete) { 130 string file_prefix = GetDirName("/writedelete_test"); 131 EventsWriter* writer = new EventsWriter(file_prefix); 132 WriteFile(writer); 133 string filename = writer->FileName(); 134 delete writer; 135 VerifyFile(filename); 136 } 137 138 TEST(EventWriter, FailFlush) { 139 string file_prefix = GetDirName("/failflush_test"); 140 EventsWriter writer(file_prefix); 141 string filename = writer.FileName(); 142 WriteFile(&writer); 143 TF_EXPECT_OK(env()->FileExists(filename)); 144 TF_ASSERT_OK(env()->DeleteFile(filename)); 145 EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code()); 146 EXPECT_FALSE(writer.Flush().ok()); 147 EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code()); 148 } 149 150 TEST(EventWriter, FailClose) { 151 string file_prefix = GetDirName("/failclose_test"); 152 EventsWriter writer(file_prefix); 153 string filename = writer.FileName(); 154 WriteFile(&writer); 155 TF_EXPECT_OK(env()->FileExists(filename)); 156 TF_ASSERT_OK(env()->DeleteFile(filename)); 157 EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code()); 158 EXPECT_FALSE(writer.Close().ok()); 159 EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code()); 160 } 161 162 TEST(EventWriter, InitWriteClose) { 163 string file_prefix = GetDirName("/initwriteclose_test"); 164 EventsWriter writer(file_prefix); 165 TF_EXPECT_OK(writer.Init()); 166 string filename0 = writer.FileName(); 167 TF_EXPECT_OK(env()->FileExists(filename0)); 168 WriteFile(&writer); 169 TF_EXPECT_OK(writer.Close()); 170 string filename1 = writer.FileName(); 171 EXPECT_EQ(filename0, filename1); 172 VerifyFile(filename1); 173 } 174 175 TEST(EventWriter, NameWriteClose) { 176 string file_prefix = GetDirName("/namewriteclose_test"); 177 EventsWriter writer(file_prefix); 178 string filename = writer.FileName(); 179 TF_EXPECT_OK(env()->FileExists(filename)); 180 WriteFile(&writer); 181 TF_EXPECT_OK(writer.Close()); 182 VerifyFile(filename); 183 } 184 185 TEST(EventWriter, NameClose) { 186 string file_prefix = GetDirName("/nameclose_test"); 187 EventsWriter writer(file_prefix); 188 string filename = writer.FileName(); 189 TF_EXPECT_OK(writer.Close()); 190 TF_EXPECT_OK(env()->FileExists(filename)); 191 TF_ASSERT_OK(env()->DeleteFile(filename)); 192 } 193 194 TEST(EventWriter, FileDeletionBeforeWriting) { 195 string file_prefix = GetDirName("/fdbw_test"); 196 EventsWriter writer(file_prefix); 197 string filename0 = writer.FileName(); 198 TF_EXPECT_OK(env()->FileExists(filename0)); 199 env()->SleepForMicroseconds( 200 2000000); // To make sure timestamp part of filename will differ. 201 TF_ASSERT_OK(env()->DeleteFile(filename0)); 202 TF_EXPECT_OK(writer.Init()); // Init should reopen file. 203 WriteFile(&writer); 204 TF_EXPECT_OK(writer.Flush()); 205 string filename1 = writer.FileName(); 206 EXPECT_NE(filename0, filename1); 207 VerifyFile(filename1); 208 } 209 210 } // namespace 211 } // namespace tensorflow 212