0

I want to write something like this to a file:

0x050 addik r13, r0, 4496
0x054 addik r2, r0, 2224
0x058 addik r1, r0, 7536
0x05c brlid r15, 200
...

And so on... Its a program instruction trace which will have thousands of lines.

I am reading from an 'elf' decoding the instruction, creating an object, setting its address, instruction, name and registers parameters and then writing it in the above format to a file.

What it is the best way, measuring in speed/performance, to do this?

Now I have this (still just hexadecimals) and I don't know if it is the best way to continue writing my code:

Converting function:

static std::string toHex(const T &i) {
    std::stringstream stream;
    stream << "0x" 
           << std::setfill ('0') << std::setw(sizeof(T)*2) 
           << std::hex << i;
    return stream.str();
};

And the writing:

while((newInstruction = manager->newInstruction())){
    stream  << Utils::toHex(newInstruction->getAddress())
            << " "
            << Utils::toHex(newInstruction->getInstruction())
            << endl;
    trace->writeFile(stream.str());
    stream.str(std::string());
}

EDIT:

So I have reached a faster solution based on the answers.

For one I implemented the solution given by Escualo to stop creating objects each time I read a new instruction.

And then I read the answer given by Thomas Matthews and gave me the idea to not write to my file at every instruction read, so the stringstream now works like a buffer with size 1024, and when it surpasses that value then writes the stream to the file:

while((newInstruction = manager->newInstruction())){
    stream  << myHex<unsigned int> << newInstruction->getAddress() << ' '
            << myHex<uint32_t> << newInstruction->getInstruction();
    if(stream.tellp() > 1024){
        trace->writeFile(stream.str());
        stream.str(std::string());
    }
}
4

2 回答 2

1

Since file I/O is slower than the time for formatting, I suggest formatting into a buffer, the block writing the buffer to the file.

char text_buffer[1024];
unsigned int bytes_formatted = 0;
for (unsigned int i = 0; i < 10; ++i)
{
  int chars_formatted = snprintf(&text_buffer[bytes_formatted],
                                 1024-bytes_formatted,
                                 "hello %d", i);
  if (chars_formatted > 0)
  {
    bytes_formatted += chars_formatted;
  }
}
my_file.write(text_buffer, bytes_formatted);

Most file I/O operations have a constant overhead regardless of the operation. So the more data that can be written during one operation, the better.

于 2015-07-10T19:15:45.393 回答
0

For one, I would avoid creating and destroying an std::stringstream for every call to your formatting function.

Recall that the I/O manipulators are nothing but functions which return the stream itself. For example, a manipulator doing exactly what you indicated above, but without resorting to a temporary std::stringstream could look like:

#include <iostream>
#include <iomanip>

template<typename T,
         typename CharT,
         typename Traits = std::char_traits<CharT> >
inline std::basic_ostream<CharT, Traits>&
myhex(std::basic_ostream<CharT, Traits>& os) {
  return os << "0x"
            << std::setfill('0')
            << std::setw(2 * sizeof(T))
            << std::hex;
}

int main() {
  int x;
  std::cout << myhex<int> << &x << std::endl;
}

to print (for example):

0x0x7fff5926cf9c

To clarify: I do not know why you choose the fill, width, prefix, and format; I am just showing you how to create an I/O manipulator that does not entail creating and destroying temporary objects.

Notice that the manipulator will work with any std::basic_ostream<CharT, Traits> such as std::cout, std::cerr, std::ofstream, and std::stringstream.

于 2015-07-10T18:40:55.227 回答