Ruby: Add support for functional accesses
Review Request #611 - Created March 29, 2011 and submitted
| Information | |
|---|---|
| Nilay Vaish | |
| gem5 | |
| default | |
| Reviewers | |
| Default | |
Ruby: Add support for functional accesses This patch rpovides functional access support in Ruby. Currently only the M5Port of RubyPort supports functional accesses. The support for functional through the PioPort will be added as a separate patch.
Diff: |
Revision 2 (+318 -120) |
|---|
Hi Nilay, First, thanks for your patience. Sorry I wasn't able to provide you comments sooner. Overall, this patch is definitely what I had in mind and is a good starting point. I have several comments/questions below. Please let me know if you need me to clarify anything.
-
src/mem/ruby/system/AbstractMemory.hh (Diff revision 2) -
Instead of having canMakeFunctionalAccess do some internal analysis and return a boolean result, why not simply pass back the AccessPermission? The status of the address for a particular memory object does not indicate whether a functional access is possible. Rather it is the collective status across all memory objects which determine whether the functional access is possible.
-
src/mem/ruby/system/CacheMemory.cc (Diff revision 2) -
Again, I think this type of analysis should be moved the RubyPort, but I do want to point out that functional accesses have different constraints than real accesses. Even if the AccessPermission is Read_Only, a functional access can succeed and should update the block.
-
src/mem/ruby/system/RubyPort.cc (Diff revision 2) -
Eventually, we'll need to change recvFunctional to return a bool indicating whether the access was successful. I suspect the ramifications of the change will be rather significant across gem5, so for now it is fine to just return void. However, eventually we will need to address this larger issue.
-
src/mem/ruby/system/RubyPort.cc (Diff revision 2) -
Are you just pushing a lable here for debug purposes? Does this have any impact on the actual functionality?
-
src/mem/ruby/system/RubyPort.cc (Diff revision 2) -
This loop is probably the most complicated and important part of this patch. It might be easiest if we move this functionality into two different functions, one for reads and one for writes. The read scan just needs to ensure that at least one memory says that it has the address in Read_Only or ReadWrite state. We may also want to doublecheck that multiple memories say they have the address in ReadWrite state. The write scan is more complicated. If one memory says that it has the address in ReadWrite state, then I don't think it matters what state the other memories are in (except of course if another memory says it also has the address in ReadWrite), the write should succeed. Also if the write scans says that all copies are in Read_Only or Invalid/NotPresent state and no copies are Busy, the write should succeed. However, writes should fail if either no Read_Only or ReadWrite copies are found, or if a Busy copy is found and no ReadWrite copy is found. The latter situation will likely indicate the functional write is racing with a timing write. There is no easy, protocol-agnostic way to resolve such a race in the current infrastructure. Make sense?
-
src/mem/ruby/system/System.hh (Diff revision 2) -
Why is this a static function? It seems unecessary and it prevents us from using ruby in multiple systems.
Diff: |
Revision 3 (+377 -122) |
|---|
This looks great, I just have a few minor suggestions below. It seems like the next step is to figure out how to deal with functional accesses not succeeding in the CPUs and devices.
-
src/mem/ruby/system/RubyPort.cc (Diff revision 3) -
Please add comments to this function explaining what is going on here.
-
src/mem/ruby/system/RubyPort.cc (Diff revision 3) -
It seems that the ro and rw counter checks should happen here, before doing any functional accesses.
-
src/mem/ruby/system/RubyPort.cc (Diff revision 3) -
Try to avoid the duplicate code between here...
-
src/mem/ruby/system/RubyPort.cc (Diff revision 3) -
...and here.
-
src/mem/ruby/system/RubyPort.cc (Diff revision 3) -
Are functional packets put on the stack or the heap? I seem to remember the former, but I could be wrong.
Hi Nilay, Comments below. I might be missing something, but the changes to DirectoryMemory seem straightforward.
-
src/mem/ruby/system/DirectoryMemory.cc (Diff revision 3) -
In the constructor for AbstractMemory, it appears that the DirectoryMemory is being added to the list of abstract memories, correct? What more do you need to do?
-
src/mem/ruby/system/DirectoryMemory.cc (Diff revision 3) -
Directory_Entry inherits from Abstract_Entry and Abstract_Entry now includes m_Permission. It seems like you can implement this function very similar to what you did with CacheMemory. Am I missing something?
-
src/mem/ruby/system/RubyPort.cc (Diff revision 3) -
You may want to add a ruby_system pointer directly to the RubyPort::M5Port to avoid at least one layer of deferencing.
Diff: |
Revision 4 (+398 -127) |
|---|
-
src/mem/ruby/system/DirectoryMemory.py (Diff revision 4) -
Why are you deleting this file and where are you moving the current functionality?
Diff: |
Revision 5 (+455 -127) |
|---|
Summary: |
|
|||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Description: |
|
|||||||||||||||
Diff: |
Revision 6 (+595 -161) |
Summary: |
|
|||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Description: |
|
|||||||||||||||
Testing Done: |
|
Hi Nilay, This patch is getting close. Comments below. There is one item in this patch that I would request other developers to comment on. Please look at Nilay's changes to packet.hh and let us know if they seem reasonable to you. The main point here is that functional requests are not guaranteed to succeed in Ruby and thus there must be some mechanism to indicate when they failed. Does passing that information back in the packet make sense? Should it be in the request instead? Other possible issues?
-
configs/example/ruby_mem_test.py (Diff revision 6) -
It seems that the following three parameters should not be hardcoded, but instead should be set using command line options. Hardcoding the atomic parameter to false still makes sense, since Ruby can handle atomic requests. Also we should update the comment above.
-
src/cpu/testers/memtest/memtest.cc (Diff revision 6) -
Remove commented out line
-
src/mem/packet.hh (Diff revision 6) -
This is more of a question to the other developers: Is this a reasonable way to return functional request failure? It works for me, but I want to get others opinion.
-
src/mem/protocol/MESI_CMP_directory-L1cache.sm (Diff revision 6) -
Why are you adding this function? SLICC already generates a similar function: getPermission(). Overall, I hope/think we can add functional access support without requiring any more changes to the protocol specific .sm files beyond the changeset: 8086:bf0335d98250 that I checked in a couple months ago.
-
src/mem/ruby/system/CacheMemory.cc (Diff revision 6) -
Why are you commenting this line out? If you think it is no longer needed, just remove it. If we remove it, can we guarentee that the permission is initialized to some value? For instance, do we know whether the "entry" constructor will allows initialize the value?
-
src/mem/ruby/system/DirectoryMemory.cc (Diff revision 6) -
Please align this statement.
-
src/mem/ruby/system/RubyPort.cc (Diff revision 6) -
Overall, I really like the comments you added in this file. They really help clarify what is going on here. Just one minor correction: change "Any copy" to "Any valid copy"
-
src/mem/ruby/system/System.hh (Diff revision 6) -
Why are these functions static? I'm concerned that declaring these static will unecessarily restrict using Ruby in multiple system simulation. Also from my understanding of the code, there is no need to make them static. Perhaps I'm missing something.
Description: |
|
|||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Diff: |
Revision 7 (+591 -162) |
Please fix these style issues, including the ones in this file I haven't explicitly pointed out. You should be using M5 style generally, but especially when your in M5 code. Also, please be sure to point this out to one of the classic memory system experts (Nate, Steve, or Ali) and get them to sign off. They might not see that this change touches outside of Ruby.
-
src/mem/packet.hh (Diff revision 6) -
Don't add commented out code.
-
src/mem/packet.hh (Diff revision 6) -
space after if, brace at the end of the line
-
src/mem/packet.hh (Diff revision 6) -
space after if, brace on the end of the line not on a new one.
-
src/mem/packet.hh (Diff revision 6) -
This should be } else {
Diff: |
Revision 8 (+584 -162) |
|---|
Thanks for pointing these changes out. I didn't look at the Ruby stuff since it looks like Brad has beaten you up plenty on that. I think it's fine to check this in initially without any support for handling errors outside of the tester. I checked and there aren't many unique calls to sendFunctional; most of the uses of functional accesses go through Port::readBlob() and Port::writeBlob(). Adding code to check the return cmd value at each call site and call warn() if it fails would be the next step in my opinion.
-
configs/example/ruby_mem_test.py (Diff revision 8) -
You probably don't want to commit this value, do you? If you want to hardwire a number, I'd pick something more reasonable (somewhere between 10 and 25, just guessing).
-
src/mem/packet.hh (Diff revision 8) -
I don't see much value in having separate error return codes for reads and writes. I'd use a single code that ends in Error (like FunctionalAccessError), and put it up a couple of lines with the other Error codes.
-
src/mem/packet.hh (Diff revision 8) -
Way too much code duplication here :-). I think this works, correct? void makeFunctionalResponse(bool success) { makeResponse(); if (!success) { cmd = MemCmd::FunctionalAccessError; } }
Description: |
|
||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Diff: |
Revision 9 (+810 -213) |
Testing Done: |
|
|---|
Summary: |
|
|||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Description: |
|
|||||||||||||||||||||||||||||||||||||||
Diff: |
Revision 10 (+641 -223) |
Summary: |
|
||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Description: |
|
||||||||||||||||||||||||
Diff: |
Revision 11 (+641 -223) |
This patch has all the functionality we need. Also I really like the inheritance structure. I have a few minor questions and suggestion below. The only significant change/question I have is regarding the ruby system pointer. Right now the pointer is passed all throughout the ruby configuration process. Instead of doing this, can you leverage the parent.any functionality? I know it can be confusing to avoid cycles in configuration, while leveraging parent.any, but it seems that the current system should work. You already do the back pointer setting in C++ through the register pointer callbacks.
-
configs/ruby/Ruby.py (Diff revision 11) -
Why are you exec the strings instead of just directly including the commands?
-
src/mem/protocol/MOESI_CMP_directory-dir.sm (Diff revision 11) -
Why are you commenting out this check? It seems to me that we can still include it, but if we cannot, we should remove the line. Don't comment it out.
-
src/mem/protocol/MOESI_hammer-cache.sm (Diff revision 11) -
Same here? Why comment this out?
-
src/mem/ruby/system/AbstractMemory.hh (Diff revision 11) -
It seems that the function "makeFunctionalAccess" is not turning a request into a functional access, but instead is actually performing the functional access. How about we split these functions to "doFunctionalRead" and "doFunctionalWrite"? That seems more appropriate and is more consistent with the rubyPort functions.
-
src/mem/ruby/system/AbstractMemory.py (Diff revision 11) -
Can you turn this into a parent any call and remove the need to pass around the ruby system pointer to all functions?
-
src/mem/ruby/system/CacheMemory.cc (Diff revision 11) -
It is possible to have a "-1" value here? It seems that one only calls this function if the getPermission function returns Read_Only or Read_Write? Therefore aren't you guaranteed to find the block?
-
src/mem/ruby/system/DirectoryMemory.cc (Diff revision 11) -
Similar thing here. It is possible to have the block not present here? It seems that one only calls this function if the getPermission function returns Read_Only or Read_Write? Therefore aren't you guaranteed to find the block?
Summary: |
|
|||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Description: |
|
|||||||||||||||||||||||||||||||||||||||
Diff: |
Revision 12 (+571 -249) |
Summary: |
|
|||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Description: |
|
Description: |
|
|||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Diff: |
Revision 13 (+572 -245) |
