Suggestions of __tm_commit, __tm_pause/__tm_restart statements in STM compiler

Suggestions of __tm_commit, __tm_pause/__tm_restart statements in STM compiler

Currently some lock-based codes are hard to be mapped to transactions due to their complexity in the control-flow structure. I think it may be worthwhile to try out somenew statements to handle this situation. For example, here is a control flow pattern: (from Apache HTTP server and PARSEC)

lock;
if(){
if(){
//stmts...
unlock;
//stmts..
}
if(){
//stmts...
unlock;
//stmts...
}
//stmts...
}else{
//stmts...
unlock;
//stmts...
}

I think a good way to handle this situation is a __tm_commit statement, which forces an early commitment of the enclosing transaction. Surely we can solve it by goto statement, which is provided by current PE2.0. However, goto is something that we should actually try to get rid of in our code, and many gotos here may make the code hard to manage. Also we may mark the whole stuff into a single atomic region, as TM is born to make coarse-grained parallelism. But experiences are there may be I/O operations following the unlock, because since I/O operations are usually slow, lock-based programs also tend to put them out of critical regions. So __tm_commit may provide opportunities to exclude such operations.

Here is another piece of code: (from Apache HTTP server)

lock
while(cond){
unlock;
//stmt...
lock;
}
unlock;

The loop body may expect the changes of condition from other threads in order to jump out of the loop or something. Thus I think the __tm_pause/__tm_restart pair may suit this situation. __tm_pause forces a commitment and pauses the transactional semantics of the ongoing transaction, and the transaction following the restart point will roll back to __tm_restart when it is aborted.

I'm not sureif they are suitable though...

5 posts / novo 0
Último post
Para obter mais informações sobre otimizações de compiladores, consulte Aviso sobre otimizações.

Alternatively, maybe we can just use __tm_begin_transaction/__tm_end_transaction statements, instead of a block,to mark a transaction , and thus itmight be much more flexible. Again it's only my guess and I don't know if its feasible.

Note, these are my opinions, so don't take them as more than that. They certainly don't reflect an "Intel view"...

So, with the disclaimers out of the way

The first piece of code you give looks like the sort of code which you don't want anyway. Are you 100% sure that all of the locks have matching unlocks, and there isn't a path through there which has abonus lock or unlock?

Transactions provide scoped locking, in the same way as C++ scoped locks (see TBB for examples). That is a much safer model, because the unlock operations are guaranteed to happen when you leave the scope of the lock object. If you like, this is similar to the difference between structured programming and gotos. The code you show is goto-like in its lock discipline, whereas lexically scoped locks are like structured code.

I'm not in favour of modifying the clean lexical scoping model of transactions to support goto-style lock disciplines

If your second example is really like this

lock
while(cond){
unlock;
//stmt...
lock;
}
unlock;

it seems easy to rewrite as


int continue = 0;
atomic { continue = cond; }
while (continue)
{
// Loop body
atomic { continue = cond; }
}

Which requires nothing more than existing language features.

"Your view" is certainly of great help And yes, your code makes it. Thanks!

Regarding to the first one, the scoped locks does give a clear look and guarantees the lock pair.While surely I don't like the code style as you guessed, that's the real code. So do you have any suggestion on mapping these kind of code to the "structured" transactions? Or just use goto to handle these "goto-like" locks?

Also, while goto is not encouraged, it is reserved. Just as non-scoped lock can also be used in TBB anyway. So maybe the presence of the non-scoping transaction, as akind of complement,can be handy in certain situations. As sometimes there is more complex structure and people may don't want torewrite them. For example, another piece of code from Apache:

if(cond1){
if(cond2){
lock;
}
//stmt1...
}else{
//stmt2...
}
//stmt3...
if(cond1&&cond2){
//stmt4...
unlock;
}

I may rewrite it as:

if(cond1){
if(cond2){
atomic{
//stmt1...
//stmt3...
//stmt4...
}
}else{
//stmt1...
//stmt3...
}
}else{
//stmt2...
//stmt3...
}

But maybe I'm not so lucky to think of this next time when I encounter another more complex structure. And sometimes it could be not so straightforward and I have to spend large amount of time thinking of it. (But I admit the rewritten code here is morestructured than the former one,despite theduplicated code )

Please applyJim's disclaimer to my post as well: this is my personalopinion from the developer's point of view.

The question brought by Jim about matching locks/unlocks has significant impact on TM'ed program correctness. It is highly desirable for STM that matching of locks and lockis done at compile time since, unlike real locks case, in STM all memory accesses between lock and unlock are specially processed by compiler. So if, by any chance, some code escapes apropriate unlock (in compiler's analysis) it will be incorrectly treated as transactional and processed accordingly leading to unpredictable results. Note that such code may be dynamically absolutely correct, but compilerwon't be able toprove this correctness (or find incorrectness)due to dependencies on, say, variables' dynamic values.

So the general problem is following: compiler is not for correct programs only - it cannot presume that program is correct. Instead it should do its best to prove correctness and help in detection and revealing possible bugs in code (better as early as possible). In the case of non-structuralSTM constructsthere will be huge opportunity for compiler to produce incorrect code even for correct program and no chance to detect real problems.

Faça login para deixar um comentário.