quipper: PerfReader stores string metadata as proto

BUG=chromium:568870
TEST=unit tests pass

Change-Id: Iac14ef57f4e40d50026f254ef46e21b29ad0d483
Signed-off-by: Simon Que <sque@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/327295
Reviewed-by: David Sharp <dhsharp@chromium.org>
diff --git a/chromiumos-wide-profiling/perf_reader.cc b/chromiumos-wide-profiling/perf_reader.cc
index 5eb3773..65f0306 100644
--- a/chromiumos-wide-profiling/perf_reader.cc
+++ b/chromiumos-wide-profiling/perf_reader.cc
@@ -26,6 +26,8 @@
 
 using PerfEvent = PerfDataProto_PerfEvent;
 using SampleInfo = PerfDataProto_SampleInfo;
+using StringAndMd5sumPrefix =
+    PerfDataProto_StringMetadata_StringAndMd5sumPrefix;
 
 namespace {
 
@@ -136,8 +138,7 @@
 }
 
 // Reads a CStringWithLength from |data| into |dest| at the current offset.
-bool ReadStringFromBuffer(DataReader* data,
-                          CStringWithLength* dest) {
+bool ReadStringFromBuffer(DataReader* data, CStringWithLength* dest) {
   if (!data->ReadUint32(&dest->len)) {
     LOG(ERROR) << "Could not read string length from data.";
     return false;
@@ -196,6 +197,11 @@
 
 }  // namespace
 
+// static
+size_t CStringWithLength::ExpectedStorageSizeOf(const string& str) {
+  return sizeof(CStringWithLength::len) + GetUint64AlignedStringLength(str);
+}
+
 PerfReader::PerfReader() : metadata_mask_(0),
                            is_cross_endian_(false) {}
 
@@ -215,6 +221,10 @@
   // Serialize metadata.
   perf_data_proto->add_metadata_mask(metadata_mask_);
   perf_data_proto->mutable_build_ids()->CopyFrom(proto_.build_ids());
+  if (proto_.has_string_metadata()) {
+    perf_data_proto->mutable_string_metadata()->
+        CopyFrom(proto_.string_metadata());
+  }
   if (!serializer_.SerializeMetadata(*this, perf_data_proto)) {
     return false;
   }
@@ -240,6 +250,10 @@
   if (perf_data_proto.metadata_mask_size())
     metadata_mask_ = perf_data_proto.metadata_mask(0);
   proto_.mutable_build_ids()->CopyFrom(perf_data_proto.build_ids());
+  if (perf_data_proto.has_string_metadata()) {
+    proto_.mutable_string_metadata()->
+        CopyFrom(perf_data_proto.string_metadata());
+  }
   if (!serializer_.DeserializeMetadata(perf_data_proto, this))
     return false;
 
@@ -912,15 +926,58 @@
         return false;
       break;
     case HEADER_HOSTNAME:
-    case HEADER_OSRELEASE:
-    case HEADER_VERSION:
-    case HEADER_ARCH:
-    case HEADER_CPUDESC:
-    case HEADER_CPUID:
-    case HEADER_CMDLINE:
-      if (!ReadStringMetadata(data, type, size))
+      if (!ReadSingleStringMetadata(
+              data, size,
+              proto_.mutable_string_metadata()->mutable_hostname())) {
         return false;
+      }
       break;
+    case HEADER_OSRELEASE:
+      if (!ReadSingleStringMetadata(
+              data, size,
+              proto_.mutable_string_metadata()->mutable_kernel_version())) {
+        return false;
+      }
+      break;
+    case HEADER_VERSION:
+      if (!ReadSingleStringMetadata(
+              data, size,
+              proto_.mutable_string_metadata()->mutable_perf_version())) {
+        return false;
+      }
+      break;
+    case HEADER_ARCH:
+      if (!ReadSingleStringMetadata(
+              data, size,
+              proto_.mutable_string_metadata()->mutable_architecture())) {
+        return false;
+      }
+      break;
+    case HEADER_CPUDESC:
+      if (!ReadSingleStringMetadata(
+              data, size,
+              proto_.mutable_string_metadata()->mutable_cpu_description())) {
+        return false;
+      }
+      break;
+    case HEADER_CPUID:
+      if (!ReadSingleStringMetadata(
+              data, size,
+              proto_.mutable_string_metadata()->mutable_cpu_id())) {
+        return false;
+      }
+      break;
+    case HEADER_CMDLINE:
+    {
+      auto* string_metadata = proto_.mutable_string_metadata();
+      if (!ReadRepeatedStringMetadata(
+              data, size,
+              string_metadata->mutable_perf_command_line_token(),
+              string_metadata->mutable_perf_command_line_whole())) {
+        return false;
+      }
+      break;
+    }
     case HEADER_NRCPUS:
       if (!ReadUint32Metadata(data, type, size))
         return false;
@@ -999,29 +1056,50 @@
   return true;
 }
 
-bool PerfReader::ReadStringMetadata(DataReader* data, u32 type, size_t size) {
-  PerfStringMetadata str_data;
-  str_data.type = type;
+bool PerfReader::ReadSingleStringMetadata(
+    DataReader* data,
+    size_t max_readable_size,
+    StringAndMd5sumPrefix* dest) const {
+  // If a string metadata field is present but empty, it can have a size of 0,
+  // in which case there is nothing to be read.
+  CStringWithLength single_string;
+  if (max_readable_size && !ReadStringFromBuffer(data, &single_string))
+    return false;
+  dest->set_value(single_string.str);
+  dest->set_value_md5_prefix(Md5Prefix(single_string.str));
+  return true;
+}
 
-  // Skip the number of string data if it is present.
-  if (NeedsNumberOfStringData(type)) {
-    num_string_data_type count;
-    if (!data->ReadUint32(&count)) {
-      LOG(ERROR) << "Error reading string count.";
+bool PerfReader::ReadRepeatedStringMetadata(
+    DataReader* data,
+    size_t max_readable_size,
+    RepeatedPtrField<StringAndMd5sumPrefix>* dest_array,
+    StringAndMd5sumPrefix* dest_single) const {
+  num_string_data_type count = 1;
+  if (!data->ReadUint32(&count)) {
+    LOG(ERROR) << "Error reading string count.";
+    return false;
+  }
+  size_t size_read = sizeof(count);
+
+  string full_string;
+  while (count-- > 0 && size_read < max_readable_size) {
+    StringAndMd5sumPrefix* new_entry = dest_array->Add();
+    size_t offset = data->Tell();
+    if (!ReadSingleStringMetadata(data, max_readable_size - size_read,
+                                  new_entry)) {
       return false;
     }
-    size -= sizeof(count);
+
+    if (!full_string.empty())
+      full_string += " ";
+    full_string += new_entry->value();
+
+    size_read += data->Tell() - offset;
   }
 
-  while (size > 0) {
-    CStringWithLength single_string;
-    if (!ReadStringFromBuffer(data, &single_string))
-      return false;
-    str_data.data.push_back(single_string);
-    size -= (sizeof(single_string.len) + single_string.len);
-  }
-
-  string_metadata_.push_back(str_data);
+  dest_single->set_value(full_string);
+  dest_single->set_value_md5_prefix(Md5Prefix(full_string));
   return true;
 }
 
@@ -1261,32 +1339,50 @@
       break;
     case PERF_RECORD_HEADER_HOSTNAME:
       metadata_mask_ |= (1 << HEADER_HOSTNAME);
-      result = ReadStringMetadata(data, HEADER_HOSTNAME, size_without_header);
+      result = ReadSingleStringMetadata(
+                   data, size_without_header,
+                   proto_.mutable_string_metadata()->mutable_hostname());
       break;
     case PERF_RECORD_HEADER_OSRELEASE:
       metadata_mask_ |= (1 << HEADER_OSRELEASE);
-      result = ReadStringMetadata(data, HEADER_OSRELEASE, size_without_header);
+      result = ReadSingleStringMetadata(
+                   data, size_without_header,
+                   proto_.mutable_string_metadata()->mutable_kernel_version());
       break;
     case PERF_RECORD_HEADER_VERSION:
       metadata_mask_ |= (1 << HEADER_VERSION);
-      result = ReadStringMetadata(data, HEADER_VERSION, size_without_header);
+      result = ReadSingleStringMetadata(
+                   data, size_without_header,
+                   proto_.mutable_string_metadata()->mutable_perf_version());
       break;
     case PERF_RECORD_HEADER_ARCH:
       metadata_mask_ |= (1 << HEADER_ARCH);
-      result = ReadStringMetadata(data, HEADER_ARCH, size_without_header);
+      result = ReadSingleStringMetadata(
+                   data, size_without_header,
+                   proto_.mutable_string_metadata()->mutable_architecture());
       break;
     case PERF_RECORD_HEADER_CPUDESC:
       metadata_mask_ |= (1 << HEADER_CPUDESC);
-      result = ReadStringMetadata(data, HEADER_CPUDESC, size_without_header);
+      result = ReadSingleStringMetadata(
+                   data, size_without_header,
+                   proto_.mutable_string_metadata()->mutable_cpu_description());
       break;
     case PERF_RECORD_HEADER_CPUID:
       metadata_mask_ |= (1 << HEADER_CPUID);
-      result = ReadStringMetadata(data, HEADER_CPUID, size_without_header);
+      result = ReadSingleStringMetadata(
+                   data, size_without_header,
+                   proto_.mutable_string_metadata()->mutable_cpu_id());
       break;
     case PERF_RECORD_HEADER_CMDLINE:
+    {
       metadata_mask_ |= (1 << HEADER_CMDLINE);
-      result = ReadStringMetadata(data, HEADER_CMDLINE, size_without_header);
+      auto* string_metadata = proto_.mutable_string_metadata();
+      result = ReadRepeatedStringMetadata(
+                   data, size_without_header,
+                   string_metadata->mutable_perf_command_line_token(),
+                   string_metadata->mutable_perf_command_line_whole());
       break;
+    }
     case PERF_RECORD_HEADER_NRCPUS:
       metadata_mask_ |= (1 << HEADER_NRCPUS);
       result = ReadUint32Metadata(data, HEADER_NRCPUS, size_without_header);
@@ -1402,6 +1498,9 @@
   std::vector<struct perf_file_section> metadata_sections;
   metadata_sections.reserve(GetNumSupportedMetadata());
 
+  // For less verbose access to string metadata fields.
+  const auto& string_metadata = proto_.string_metadata();
+
   for (u32 type = HEADER_FIRST_FEATURE; type != HEADER_LAST_FEATURE; ++type) {
     if ((header.adds_features[0] & (1 << type)) == 0)
       continue;
@@ -1421,15 +1520,36 @@
         return false;
       break;
     case HEADER_HOSTNAME:
-    case HEADER_OSRELEASE:
-    case HEADER_VERSION:
-    case HEADER_ARCH:
-    case HEADER_CPUDESC:
-    case HEADER_CPUID:
-    case HEADER_CMDLINE:
-      if (!WriteStringMetadata(type, data))
+      if (!WriteSingleStringMetadata(string_metadata.hostname(), data))
         return false;
       break;
+    case HEADER_OSRELEASE:
+      if (!WriteSingleStringMetadata(string_metadata.kernel_version(), data))
+        return false;
+      break;
+    case HEADER_VERSION:
+      if (!WriteSingleStringMetadata(string_metadata.perf_version(), data))
+        return false;
+      break;
+    case HEADER_ARCH:
+      if (!WriteSingleStringMetadata(string_metadata.architecture(), data))
+        return false;
+      break;
+    case HEADER_CPUDESC:
+      if (!WriteSingleStringMetadata(string_metadata.cpu_description(), data))
+        return false;
+      break;
+    case HEADER_CPUID:
+      if (!WriteSingleStringMetadata(string_metadata.cpu_id(), data))
+        return false;
+      break;
+    case HEADER_CMDLINE:
+      if (!WriteRepeatedStringMetadata(
+              string_metadata.perf_command_line_token(),
+              data)) {
+        return false;
+      }
+      break;
     case HEADER_NRCPUS:
       if (!WriteUint32Metadata(type, data))
         return false;
@@ -1496,28 +1616,31 @@
   return true;
 }
 
-bool PerfReader::WriteStringMetadata(u32 type, DataWriter* data) const {
-  for (size_t i = 0; i < string_metadata_.size(); ++i) {
-    const PerfStringMetadata& str_data = string_metadata_[i];
-    if (str_data.type == type) {
-      num_string_data_type num_strings = str_data.data.size();
-      if (NeedsNumberOfStringData(type) &&
-          !data->WriteDataValue(&num_strings, sizeof(num_strings),
-                                "number of string metadata")) {
-        return false;
-      }
+bool PerfReader::WriteSingleStringMetadata(
+    const StringAndMd5sumPrefix& src,
+    DataWriter* data) const {
+  CStringWithLength string_with_length;
+  string_with_length.str = src.value();
+  string_with_length.len = GetUint64AlignedStringLength(src.value());
+  return WriteStringToBuffer(string_with_length, data);
+}
 
-      for (size_t j = 0; j < num_strings; ++j) {
-        const CStringWithLength& single_string = str_data.data[j];
-        if (!WriteStringToBuffer(single_string, data))
-          return false;
-      }
-
-      return true;
-    }
+bool PerfReader::WriteRepeatedStringMetadata(
+    const RepeatedPtrField<StringAndMd5sumPrefix>& src_array,
+    DataWriter* data) const {
+  num_string_data_type num_strings = src_array.size();
+  if (!data->WriteDataValue(&num_strings, sizeof(num_strings),
+                           "number of string metadata")) {
+    return false;
   }
-  LOG(ERROR) << "String metadata of type " << type << " not present";
-  return false;
+  for (const auto src_entry : src_array) {
+    CStringWithLength string_with_length;
+    string_with_length.str = src_entry.value();
+    string_with_length.len = GetUint64AlignedStringLength(src_entry.value());
+    if (!WriteStringToBuffer(string_with_length, data))
+      return false;
+  }
+  return true;
 }
 
 bool PerfReader::WriteUint32Metadata(u32 type, DataWriter* data) const {
@@ -1778,16 +1901,25 @@
 }
 
 size_t PerfReader::GetStringMetadataSize() const {
+  auto ExpectedStorageSizeOf = CStringWithLength::ExpectedStorageSizeOf;
   size_t size = 0;
-  for (size_t i = 0; i < string_metadata_.size(); ++i) {
-    const PerfStringMetadata& metadata = string_metadata_[i];
-    if (NeedsNumberOfStringData(metadata.type))
-      size += sizeof(num_string_data_type);
+  if (string_metadata().has_hostname())
+    size += ExpectedStorageSizeOf(string_metadata().hostname().value());
+  if (string_metadata().has_kernel_version())
+    size += ExpectedStorageSizeOf(string_metadata().kernel_version().value());
+  if (string_metadata().has_perf_version())
+    size += ExpectedStorageSizeOf(string_metadata().perf_version().value());
+  if (string_metadata().has_architecture())
+    size += ExpectedStorageSizeOf(string_metadata().architecture().value());
+  if (string_metadata().has_cpu_description())
+    size += ExpectedStorageSizeOf(string_metadata().cpu_description().value());
+  if (string_metadata().has_cpu_id())
+    size += ExpectedStorageSizeOf(string_metadata().cpu_id().value());
 
-    for (size_t j = 0; j < metadata.data.size(); ++j) {
-      const CStringWithLength& str = metadata.data[j];
-      size += sizeof(str.len) + str.len;
-    }
+  if (!string_metadata().perf_command_line_token().empty()) {
+    size += sizeof(num_string_data_type);
+    for (const auto& token : string_metadata().perf_command_line_token())
+      size += ExpectedStorageSizeOf(token.value());
   }
   return size;
 }
diff --git a/chromiumos-wide-profiling/perf_reader.h b/chromiumos-wide-profiling/perf_reader.h
index 326d2bc..20f7c24 100644
--- a/chromiumos-wide-profiling/perf_reader.h
+++ b/chromiumos-wide-profiling/perf_reader.h
@@ -38,14 +38,22 @@
 const size_t kBuildIDArraySize = 20;
 const size_t kBuildIDStringLength = kBuildIDArraySize * 2;
 
+// TODO(sque): Move this to perf_reader.cc once it is no longer used in this
+// file.
 struct CStringWithLength {
   u32 len;
   string str;
-};
 
-struct PerfStringMetadata {
-  u32 type;
-  std::vector<CStringWithLength> data;
+  // Returns the size required to store both |len| and a string of size |len|.
+  // This is not the same as the minimum size required to store |str|.
+  size_t GetStorageSize() const {
+    return sizeof(len) + len;
+  }
+
+  // Given a string, returns the total size required to store the string in perf
+  // data, including a preceding length field and extra padding to align the
+  // string + null terminator to a multiple of uint64s.
+  static size_t ExpectedStorageSizeOf(const string& str);
 };
 
 struct PerfUint32Metadata {
@@ -175,11 +183,8 @@
     metadata_mask_ = mask;
   }
 
-  const std::vector<PerfStringMetadata>& string_metadata() const {
-    return string_metadata_;
-  }
-  std::vector<PerfStringMetadata>* mutable_string_metadata() {
-    return &string_metadata_;
+  const PerfDataProto_StringMetadata& string_metadata() const {
+    return proto_.string_metadata();
   }
 
   const std::vector<PerfUint32Metadata>& uint32_metadata() const {
@@ -235,7 +240,23 @@
   bool ReadBuildIDMetadataWithoutHeader(DataReader* data,
                                         const perf_event_header& header);
 
-  bool ReadStringMetadata(DataReader* data, u32 type, size_t size);
+  // Reads a singular string metadata field (with preceding size field) from
+  // |data| and writes the string and its Md5sum prefix into |dest|.
+  bool ReadSingleStringMetadata(
+      DataReader* data,
+      size_t max_readable_size,
+      PerfDataProto_StringMetadata_StringAndMd5sumPrefix* dest) const;
+  // Reads a string metadata with multiple string fields (each with preceding
+  // size field) from |data|. Writes each string field and its Md5sum prefix
+  // into |dest_array|. Writes the combined string fields (joined into one
+  // string into |dest_single|.
+  bool ReadRepeatedStringMetadata(
+      DataReader* data,
+      size_t max_readable_size,
+      RepeatedPtrField<PerfDataProto_StringMetadata_StringAndMd5sumPrefix>*
+          dest_array,
+      PerfDataProto_StringMetadata_StringAndMd5sumPrefix* dest_single) const;
+
   bool ReadUint32Metadata(DataReader* data, u32 type, size_t size);
   bool ReadUint64Metadata(DataReader* data, u32 type, size_t size);
   bool ReadCPUTopologyMetadata(DataReader* data, u32 type, size_t size);
@@ -266,7 +287,13 @@
 
   // For writing the various types of metadata.
   bool WriteBuildIDMetadata(u32 type, DataWriter* data) const;
-  bool WriteStringMetadata(u32 type, DataWriter* data) const;
+  bool WriteSingleStringMetadata(
+      const PerfDataProto_StringMetadata_StringAndMd5sumPrefix& src,
+      DataWriter* data) const;
+  bool WriteRepeatedStringMetadata(
+      const RepeatedPtrField<
+          PerfDataProto_StringMetadata_StringAndMd5sumPrefix>& src_array,
+      DataWriter* data) const;
   bool WriteUint32Metadata(u32 type, DataWriter* data) const;
   bool WriteUint64Metadata(u32 type, DataWriter* data) const;
   bool WriteEventDescMetadata(u32 type, DataWriter* data) const;
@@ -313,7 +340,6 @@
   // TODO(sque): Store all fields in here, not just events.
   PerfDataProto proto_;
 
-  std::vector<PerfStringMetadata> string_metadata_;
   std::vector<PerfUint32Metadata> uint32_metadata_;
   std::vector<PerfUint64Metadata> uint64_metadata_;
   PerfCPUTopologyMetadata cpu_topology_;
diff --git a/chromiumos-wide-profiling/perf_reader_test.cc b/chromiumos-wide-profiling/perf_reader_test.cc
index 2063123..3f3acb9 100644
--- a/chromiumos-wide-profiling/perf_reader_test.cc
+++ b/chromiumos-wide-profiling/perf_reader_test.cc
@@ -833,26 +833,13 @@
   PerfReader pr;
   ASSERT_TRUE(pr.ReadFromString(input.str()));
 
+  // The dummy metadata should not have prevented the reading of the other
+  // metadata.
   const auto& string_metadata = pr.string_metadata();
-
-  // The dummy metadata should not have been stored.
-  EXPECT_EQ(4, string_metadata.size());
-
-  // Make sure each metadata entry has a stored string value.
-  for (const auto& entry : string_metadata)
-    EXPECT_EQ(1, entry.data.size());
-
-  EXPECT_EQ(HEADER_HOSTNAME, string_metadata[0].type);
-  EXPECT_EQ("hostname", string_metadata[0].data[0].str);
-
-  EXPECT_EQ(HEADER_OSRELEASE, string_metadata[1].type);
-  EXPECT_EQ("osrelease", string_metadata[1].data[0].str);
-
-  EXPECT_EQ(HEADER_VERSION, string_metadata[2].type);
-  EXPECT_EQ("version", string_metadata[2].data[0].str);
-
-  EXPECT_EQ(HEADER_ARCH, string_metadata[3].type);
-  EXPECT_EQ("arch", string_metadata[3].data[0].str);
+  EXPECT_EQ("hostname", string_metadata.hostname().value());
+  EXPECT_EQ("osrelease", string_metadata.kernel_version().value());
+  EXPECT_EQ("version", string_metadata.perf_version().value());
+  EXPECT_EQ("arch", string_metadata.architecture().value());
 }
 
 // Regression test for http://crbug.com/493533
@@ -884,26 +871,13 @@
   PerfReader pr;
   ASSERT_TRUE(pr.ReadFromString(input.str()));
 
+  // The dummy metadata should not have prevented the reading of the other
+  // metadata.
   const auto& string_metadata = pr.string_metadata();
-
-  // The dummy metadata should not have been stored.
-  EXPECT_EQ(4, string_metadata.size());
-
-  // Make sure each metadata entry has a stored string value.
-  for (const auto& entry : string_metadata)
-    EXPECT_EQ(1, entry.data.size());
-
-  EXPECT_EQ(HEADER_HOSTNAME, string_metadata[0].type);
-  EXPECT_EQ("hostname", string_metadata[0].data[0].str);
-
-  EXPECT_EQ(HEADER_OSRELEASE, string_metadata[1].type);
-  EXPECT_EQ("osrelease", string_metadata[1].data[0].str);
-
-  EXPECT_EQ(HEADER_VERSION, string_metadata[2].type);
-  EXPECT_EQ("version", string_metadata[2].data[0].str);
-
-  EXPECT_EQ(HEADER_ARCH, string_metadata[3].type);
-  EXPECT_EQ("arch", string_metadata[3].data[0].str);
+  EXPECT_EQ("hostname", string_metadata.hostname().value());
+  EXPECT_EQ("osrelease", string_metadata.kernel_version().value());
+  EXPECT_EQ("version", string_metadata.perf_version().value());
+  EXPECT_EQ("arch", string_metadata.architecture().value());
 }
 
 TEST(PerfReaderTest, AttrsWithDifferentSampleTypes) {
diff --git a/chromiumos-wide-profiling/perf_serializer.cc b/chromiumos-wide-profiling/perf_serializer.cc
index bb8da86..1d8c896 100644
--- a/chromiumos-wide-profiling/perf_serializer.cc
+++ b/chromiumos-wide-profiling/perf_serializer.cc
@@ -768,71 +768,6 @@
                                      to->mutable_numa_topology())) {
     return false;
   }
-  typedef PerfDataProto_StringMetadata_StringAndMd5sumPrefix
-      StringAndMd5sumPrefix;
-  // Handle the string metadata specially.
-  for (const auto& metadata : from.string_metadata()) {
-    StringAndMd5sumPrefix* to_metadata = NULL;
-    PerfDataProto_StringMetadata* proto_string_metadata =
-        to->mutable_string_metadata();
-    bool is_command_line = false;
-
-    switch (metadata.type) {
-    case HEADER_HOSTNAME:
-      to_metadata = proto_string_metadata->mutable_hostname();
-      break;
-    case HEADER_OSRELEASE:
-      to_metadata = proto_string_metadata->mutable_kernel_version();
-      break;
-    case HEADER_VERSION:
-      to_metadata = proto_string_metadata->mutable_perf_version();
-      break;
-    case HEADER_ARCH:
-      to_metadata = proto_string_metadata->mutable_architecture();
-      break;
-    case HEADER_CPUDESC:
-      to_metadata = proto_string_metadata->mutable_cpu_description();
-      break;
-    case HEADER_CPUID:
-      to_metadata = proto_string_metadata->mutable_cpu_id();
-      break;
-    case HEADER_CMDLINE:
-      is_command_line = true;
-      to_metadata = proto_string_metadata->mutable_perf_command_line_whole();
-      break;
-    default:
-      LOG(ERROR) << "Unsupported string metadata type: " << metadata.type;
-      continue;
-    }
-    if (is_command_line) {
-      // Handle command lines as a special case. It has two protobuf fields, one
-      // of which is a repeated field.
-      string full_command_line;
-      for (const auto& data : metadata.data) {
-        StringAndMd5sumPrefix* command_line_token =
-                proto_string_metadata->add_perf_command_line_token();
-        command_line_token->set_value(data.str);
-        command_line_token->
-            set_value_md5_prefix(Md5Prefix(command_line_token->value()));
-        full_command_line += data.str + " ";
-      }
-      // Delete the extra space at the end of the newly created command string.
-      TrimWhitespace(&full_command_line);
-      to_metadata->set_value(full_command_line);
-      to_metadata->set_value_md5_prefix(Md5Prefix(full_command_line));
-    } else {
-      DCHECK(to_metadata);  // Make sure a valid destination metadata was found.
-      // In some cases there is a null or empty string metadata value in the
-      // perf data. Make sure not to access |string_metadata_[i].data[0]| if
-      // that is the case.
-      if (!metadata.data.empty())
-        to_metadata->set_value(metadata.data[0].str);
-      else
-        to_metadata->set_value(string());
-
-      to_metadata->set_value_md5_prefix(Md5Prefix(to_metadata->value()));
-    }
-  }
   return true;
 }
 
@@ -850,63 +785,6 @@
     return false;
   }
 
-  // Handle the string metadata specially.
-  typedef PerfDataProto_StringMetadata_StringAndMd5sumPrefix
-      StringAndMd5sumPrefix;
-  const PerfDataProto_StringMetadata& data = from.string_metadata();
-  std::vector<std::pair<u32, StringAndMd5sumPrefix> > metadata_strings;
-  if (data.has_hostname()) {
-    metadata_strings.push_back(
-        std::make_pair(static_cast<u32>(HEADER_HOSTNAME), data.hostname()));
-  }
-  if (data.has_kernel_version()) {
-    metadata_strings.push_back(
-        std::make_pair(static_cast<u32>(HEADER_OSRELEASE),
-                       data.kernel_version()));
-  }
-  if (data.has_perf_version()) {
-    metadata_strings.push_back(
-        std::make_pair(static_cast<u32>(HEADER_VERSION), data.perf_version()));
-  }
-  if (data.has_architecture()) {
-    metadata_strings.push_back(
-        std::make_pair(static_cast<u32>(HEADER_ARCH), data.architecture()));
-  }
-  if (data.has_cpu_description()) {
-    metadata_strings.push_back(
-        std::make_pair(static_cast<u32>(HEADER_CPUDESC),
-                       data.cpu_description()));
-  }
-  if (data.has_cpu_id()) {
-    metadata_strings.push_back(
-        std::make_pair(static_cast<u32>(HEADER_CPUID), data.cpu_id()));
-  }
-
-  // Add each string metadata element to |string_metadata_|.
-  for (size_t i = 0; i < metadata_strings.size(); ++i) {
-    PerfStringMetadata metadata;
-    metadata.type = metadata_strings[i].first;
-    CStringWithLength cstring;
-    cstring.str = metadata_strings[i].second.value();
-    cstring.len = cstring.str.size() + 1;   // Include the null terminator.
-    metadata.data.push_back(cstring);
-
-    to->mutable_string_metadata()->push_back(metadata);
-  }
-
-  // Add the command line tokens as a special case (repeated field).
-  if (data.perf_command_line_token_size() > 0) {
-    PerfStringMetadata metadata;
-    metadata.type = HEADER_CMDLINE;
-    for (int i = 0; i < data.perf_command_line_token_size(); ++i) {
-      CStringWithLength cstring;
-      cstring.str = data.perf_command_line_token(i).value();
-      cstring.len = cstring.str.size() + 1;   // Include the null terminator.
-      metadata.data.push_back(cstring);
-    }
-    to->mutable_string_metadata()->push_back(metadata);
-  }
-
   return true;
 }