{"action":"opened","issue":{"url":"https://api.github.com/repos/eclipse/openj9/issues/2484","repository_url":"https://api.github.com/repos/eclipse/openj9","labels_url":"https://api.github.com/repos/eclipse/openj9/issues/2484/labels{/name}","comments_url":"https://api.github.com/repos/eclipse/openj9/issues/2484/comments","events_url":"https://api.github.com/repos/eclipse/openj9/issues/2484/events","html_url":"https://github.com/eclipse/openj9/issues/2484","id":344705430,"node_id":"MDU6SXNzdWUzNDQ3MDU0MzA=","number":2484,"title":"Incorporating Restricted Transactional Memory (RTM) and Hardware Lock Elision (HLE) into J9 Locking ","user":{"login":"babsingh","id":8634038,"node_id":"MDQ6VXNlcjg2MzQwMzg=","avatar_url":"https://avatars1.githubusercontent.com/u/8634038?v=4","gravatar_id":"","url":"https://api.github.com/users/babsingh","html_url":"https://github.com/babsingh","followers_url":"https://api.github.com/users/babsingh/followers","following_url":"https://api.github.com/users/babsingh/following{/other_user}","gists_url":"https://api.github.com/users/babsingh/gists{/gist_id}","starred_url":"https://api.github.com/users/babsingh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/babsingh/subscriptions","organizations_url":"https://api.github.com/users/babsingh/orgs","repos_url":"https://api.github.com/users/babsingh/repos","events_url":"https://api.github.com/users/babsingh/events{/privacy}","received_events_url":"https://api.github.com/users/babsingh/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-07-26T05:59:19Z","updated_at":"2018-07-26T05:59:19Z","closed_at":null,"author_association":"CONTRIBUTOR","body":"##  Restricted Transactional Memory (RTM)\r\n\r\nFour assembly language instructions for RTM:\r\n- `xbegin`: begin a transaction\r\n- `xend`: end a transaction\r\n- `xabort`: abort a transaction\r\n- `xtest`: check if a transaction is happening\r\n\r\nThe code to start/end a transaction is generic, and we can introduce **new APIs in OMR** for using transactional memory features.\r\n\r\nIntel article [[1]](https://software.intel.com/en-us/articles/tsx-anti-patterns-in-lock-elision-code) provides all requirements and details to the new API for transactional memory.\r\n\r\n```\r\nuint32_t \r\nstartTransaction(omrthread_monitor_t monitor, transaction_heuristics_t heuristics)\r\n{\r\n    int retries = heuristics->retries;\r\n    for (i = 0; i < retries; i++) {\r\n        if ((status = _xbegin()) == _XBEGIN_STARTED) {\r\n            if (monitor is free) {\r\n                return SUCCESS; /* Execute critical region */\r\n            }\r\n            _xabort(0xff); /* lock busy */\r\n        }\r\n        if ((status & _XABORT_EXPLICIT) && _XABORT_CODE(status) == 0xff) {\r\n            Wait for lock to become free\r\n        } else if (!(status & _XABORT_RETRY))\r\n            break;\r\n        }\r\n    }\r\n     return FAIL;\r\n}\r\n```\r\n\r\nThe main body of the above function is taken from [[1]](https://software.intel.com/en-us/articles/tsx-anti-patterns-in-lock-elision-code).\r\n\r\n`Wait for lock to become free`: This can be achieved using any of the following functions – `VM_AtomicSupport::yieldCPU()`, `omrthread_yield()`, `omrthread_yield_new(...)` or `_mm_pause()`.\r\n\r\nIf `startTransaction` succeeds, then the monitor doesn't need to be acquired. If `startTransaction` fails, then monitor should be acquired as the fallback path. If needed, a new flag can be added to `omrthread_monitor_t->flags` to indicate a transaction is taking place: `OMRTHREAD_MONITOR_TRANSACTION`.\r\n\r\n```\r\nuint32_t \r\nendTransaction(omrthread_monitor_t monitor)\r\n{\r\n    if (monitor is free) {\r\n        _xend();\r\n       return SUCCESS;\r\n    }\r\n    return FAIL;\r\n}\r\n```\r\n\r\nIf `endTransaction` succeeds, then the monitor doesn't need to be released because the monitor won't be acquired during a transaction. If `endTransaction` fails (monitor is not free), then the monitor should be released.\r\n\r\nThe definition of `omrthread_monitor_t` (`J9ThreadMonitor`) is here: \r\ni) [J9ThreadMonitor definition Part 1](https://github.com/eclipse/omr/blob/e2baea03b8cc06f247c27a0a71b42b40379a0cf6/include_core/thrtypes.h#L63).\r\nii) [J9ThreadMonitor definition Part 2](https://github.com/eclipse/omr/blob/97107f4d8b0d076e8f848d11e9fae8dc521e0b94/include_core/omrthread_generated.h#L193)\r\n\r\n### Where should `startTransaction` be added?\r\n\r\n`startTransaction` should be executed before executing the spinlock loop. There are three spin loops:\r\n[a] [`spinOnFlatLock`](https://github.com/eclipse/openj9/blob/master/runtime/vm/ObjectMonitor.cpp#L360)\r\n[b] [`spinOnTryEnter`](https://github.com/eclipse/openj9/blob/master/runtime/vm/ObjectMonitor.cpp#L448) -> [`omrthread_monitor_try_enter_using_threadId`](https://github.com/eclipse/omr/blob/master/thread/common/omrthread.c#L3995) -> [`omrthread_spinlock_acquire_no_spin`](https://github.com/eclipse/omr/blob/80b41f44ec5611972e6fb231227559f9e2cb7486/thread/common/threadhelpers.cpp#L155)\r\n[c] [`omrthread_spinlock_acquire`](https://github.com/eclipse/omr/blob/80b41f44ec5611972e6fb231227559f9e2cb7486/thread/common/threadhelpers.cpp#L54)\r\n\r\nIn J9, an inflated lock can be associated to `omrthread_monitor_t`. `spinOnTryEnter` [a] and  `omrthread_spinlock_acquire` [b] loop on the inflated lock (`omrthread_monitor_t`). `startTransaction` should be added at the start of [a] and [b].\r\n\r\n### Where should `endTransaction` be added?\r\n\r\ni) If the start point is `omrthread_monitor_enter` -> ... -> `omrthread_spinlock_acquire`, then the end point would be `omrthread_monitor_exit` -> `monitor_exit`. So, one place for endTransaction would be the start of [`monitor_exit`](https://github.com/eclipse/omr/blob/master/thread/common/omrthread.c#L4112).\r\nii) In `spinOnTryEnter`, `startTransaction` should only be attempted if the lock is inflated [`J9_LOCK_IS_INFLATED(*lwEA)`]. For the inflated scenario, the following code path will be taken: `objectMonitorExit` -> `omrthread_monitor_exit` -> `monitor_exit`. So, the end point for `omrthread_spinlock_acquire` and `spinOnTryEnter` (inflated scenario) should be the same. This seems tricky. We can ignore `spinOnTryEnter` at the beginning if issues are encountered.\r\n\r\n## Hardware Lock Ellision (HLE)\r\n\r\nTwo assembly instructions for HLE:\r\n- `xacquire`: prefix to the instruction acquiring lock\r\n- `xrelease`: prefix to the instruction releasing lock\r\n\r\n```\r\nvoid hle_spin_lock(int *lock)\r\n{\r\n    while ((int)__hle_acquire_sub_fetch4(&lock, 1) < 0) {\r\n        /* spin until the lock is free before retrying */\r\n        while (*lock != 1)\r\n            _mm_pause(); /* Re-read lock and abort. */\r\n    }\r\n}\r\n```\r\nThe above code snippet is taken from [[1]](https://software.intel.com/en-us/articles/tsx-anti-patterns-in-lock-elision-code).\r\n\r\n` __hle_acquire_or_fetch4(&foo, 1)` \r\n`__atomic_or_fetch(&foo, 1, __ATOMIC_ACQUIRE|__ATOMIC_HLE_ACQUIRE) `\r\n\r\n`_hle_acquire_or_fetch4` is equivalent to `__atomic_or_fetch` [with XACQUIRE HLE prefix]\r\n\r\nIn spin loops [b] and [c], `VM_AtomicSupport::lockCompareExchange` can be replaced with a compare exchange that has a XACQUIRE HLE prefix.\r\n\r\n## Compiler requirements\r\ngcc4.8+ **[Need to be verified]**\r\n\r\n## References:\r\n[1] https://software.intel.com/en-us/articles/tsx-anti-patterns-in-lock-elision-code\r\n[2] https://software.intel.com/en-us/blogs/2013/05/20/using-hle-and-rtm-with-older-compilers-with-tsx-tools\r\n[3] https://www.scss.tcd.ie/Jeremy.Jones/CS4021/transactional%20memory.pdf"}}
{"actor":{"display_login":"babsingh"}}