submission 415922
oofbaroomf · python · License unknown
Use it
Vendorable · source mirrored · license unknownView source →
No package. Vendor the mirrored source: 945 lines, June 9 Researcher Reciprocity License v1.0.
submission_ext_2sm_m128.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-nvfp4-group-gemm-415922?include=source"interfacepython
Compatibility
measured onNVIDIA B200
declared hardwareNVIDIA B200
architecturessm_100
dtypesfp8_e4m3, nvfp4
Benchmark evidence
1 measurement across 1 GPU, fastest first.
Operation / workload
Hardware
Latency
Rank
Observed
Reported · How evidence levels are derived →
Source and license
sourceavailable
revision digestsha256:5650253e731cf9c078ca2916692196b95a05eb2d21a72b02163e30ff8ae1ab44
license declaredunknown
license concludedunknown
authorsoofbaroomf
imported2026-08-15
Kernel source
submission_ext_2sm_m128.py945 lines
import base64
import os
import torch
from task import input_t, output_t
try:
torch.backends.cuda.matmul.allow_fp16_reduced_precision_reduction = True
torch.backends.cuda.matmul.allow_bf16_reduced_precision_reduction = True
except Exception:
pass
_CPP_B64 = "CiAgICAjaW5jbHVkZSA8dG9yY2gvZXh0ZW5zaW9uLmg+CiAgICAjaW5jbHVkZSA8dmVjdG9yPgoKICAgIHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+IGdyb3VwZWRfZ2VtbV8xc20oCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIEEsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIEIsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIEMsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIFNGQSwKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgU0ZCKTsKCiAgICBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiBncm91cGVkX2dlbW1fMnNtKAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBBLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBCLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBDLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBTRkEsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIFNGQik7CiAgICA="
_CU_B64 = "CiAgICAjaW5jbHVkZSA8dG9yY2gvZXh0ZW5zaW9uLmg+CiAgICAjaW5jbHVkZSA8QVRlbi9jdWRhL0NVREFDb250ZXh0Lmg+CiAgICAjaW5jbHVkZSA8YzEwL2N1ZGEvQ1VEQVN0cmVhbS5oPgogICAgI2luY2x1ZGUgPGMxMC9jdWRhL0NVREFHdWFyZC5oPgogICAgI2luY2x1ZGUgPHZlY3Rvcj4KICAgICNpbmNsdWRlIDxzdGRleGNlcHQ+CiAgICAjaW5jbHVkZSA8dHlwZV90cmFpdHM+CgogICAgI2lmZGVmIF9fQ1VEQV9OT19IQUxGX09QRVJBVE9SU19fCiAgICAjdW5kZWYgX19DVURBX05PX0hBTEZfT1BFUkFUT1JTX18KICAgICNlbmRpZgogICAgI2lmZGVmIF9fQ1VEQV9OT19IQUxGX0NPTlZFUlNJT05TX18KICAgICN1bmRlZiBfX0NVREFfTk9fSEFMRl9DT05WRVJTSU9OU19fCiAgICAjZW5kaWYKICAgICNpZmRlZiBfX0NVREFfTk9fSEFMRjJfT1BFUkFUT1JTX18KICAgICN1bmRlZiBfX0NVREFfTk9fSEFMRjJfT1BFUkFUT1JTX18KICAgICNlbmRpZgoKICAgICNpbmNsdWRlIDxjdWRhX3J1bnRpbWUuaD4KICAgICNpZiBkZWZpbmVkKF9fQ1VEQV9BUkNIX18pICYmICFkZWZpbmVkKENVVExBU1NfQVJDSF9NTUFfU00xMDBBX0VOQUJMRUQpCiAgICAjZGVmaW5lIENVVExBU1NfQVJDSF9NTUFfU00xMDBBX0VOQUJMRUQgMQogICAgI2VuZGlmCiAgICAjaW5jbHVkZSAiY3V0bGFzcy9jdXRsYXNzLmgiCiAgICAjaW5jbHVkZSAiY3V0ZS90ZW5zb3IuaHBwIgogICAgI2luY2x1ZGUgImN1dGxhc3MvdGVuc29yX3JlZi5oIgogICAgI2luY2x1ZGUgImN1dGxhc3MvZXBpbG9ndWUvY29sbGVjdGl2ZS9kZWZhdWx0X2VwaWxvZ3VlLmhwcCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2VwaWxvZ3VlL3RocmVhZC9saW5lYXJfY29tYmluYXRpb24uaCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2dlbW0vZGlzcGF0Y2hfcG9saWN5LmhwcCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2dlbW0vZ3JvdXBfYXJyYXlfcHJvYmxlbV9zaGFwZS5ocHAiCiAgICAjaW5jbHVkZSAiY3V0bGFzcy9nZW1tL2NvbGxlY3RpdmUvY29sbGVjdGl2ZV9idWlsZGVyLmhwcCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2VwaWxvZ3VlL2NvbGxlY3RpdmUvY29sbGVjdGl2ZV9idWlsZGVyLmhwcCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2dlbW0vZGV2aWNlL2dlbW1fdW5pdmVyc2FsX2FkYXB0ZXIuaCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2dlbW0va2VybmVsL2dlbW1fdW5pdmVyc2FsLmhwcCIKICAgICNpbmNsdWRlICJjdXRsYXNzL3V0aWwvcGFja2VkX3N0cmlkZS5ocHAiCiAgICAjaW5jbHVkZSAiY3V0bGFzcy9rZXJuZWxfaGFyZHdhcmVfaW5mby5oIgogICAgI2luY2x1ZGUgImN1dGxhc3MvdXRpbC9kZXZpY2VfbWVtb3J5LmgiCiAgICAjaW5jbHVkZSAiY3V0bGFzcy9nZW1tL2tlcm5lbC90aWxlX3NjaGVkdWxlcl9wYXJhbXMuaCIKCiAgICAjZGVmaW5lIENVVExBU1NfQ0hFQ0soc3RhdHVzKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXAogICAgICBkbyB7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwKICAgICAgICBjdXRsYXNzOjpTdGF0dXMgX3N0YXR1cyA9IChzdGF0dXMpOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcCiAgICAgICAgaWYgKF9zdGF0dXMgIT0gY3V0bGFzczo6U3RhdHVzOjprU3VjY2VzcykgeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXAogICAgICAgICAgdGhyb3cgc3RkOjpydW50aW1lX2Vycm9yKCJDVVRMQVNTIGVycm9yIik7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwKICAgICAgICB9ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcCiAgICAgIH0gd2hpbGUgKDApCgogICAgI2RlZmluZSBDVURBX0NIRUNLKGV4cHIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXAogICAgICBkbyB7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwKICAgICAgICBjdWRhRXJyb3JfdCBfZXJyID0gKGV4cHIpOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcCiAgICAgICAgaWYgKF9lcnIgIT0gY3VkYVN1Y2Nlc3MpIHsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXAogICAgICAgICAgdGhyb3cgc3RkOjpydW50aW1lX2Vycm9yKGN1ZGFHZXRFcnJvclN0cmluZyhfZXJyKSk7ICAgICAgICAgICAgICAgICAgICAgICAgIFwKICAgICAgICB9ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcCiAgICAgIH0gd2hpbGUgKDApCgogICAgdXNpbmcgUHJvYmxlbVNoYXBlID0gY3V0bGFzczo6Z2VtbTo6R3JvdXBQcm9ibGVtU2hhcGU8Y3V0ZTo6U2hhcGU8aW50LGludCxpbnQ+PjsKICAgIHVzaW5nIEVsZW1lbnRJbnB1dCA9IGN1dGxhc3M6OmZsb2F0X2UybTFfdDsKICAgIHVzaW5nIEVsZW1lbnRTRiAgICA9IGN1dGxhc3M6OmZsb2F0X3VlNG0zX3Q7CiAgICB1c2luZyBFbGVtZW50QyAgICAgPSBjdXRsYXNzOjpoYWxmX3Q7CgogICAgdXNpbmcgRWxlbWVudEEgPSBjdXRsYXNzOjpudl9mbG9hdDRfdDxFbGVtZW50SW5wdXQ+OwogICAgdXNpbmcgTGF5b3V0QSAgPSBjdXRsYXNzOjpsYXlvdXQ6OlJvd01ham9yOwogICAgY29uc3RleHByIGludCBBbGlnbm1lbnRBICA9IDMyOwoKICAgIHVzaW5nIEVsZW1lbnRCID0gY3V0bGFzczo6bnZfZmxvYXQ0X3Q8RWxlbWVudElucHV0PjsKICAgIHVzaW5nIExheW91dEIgID0gY3V0bGFzczo6bGF5b3V0OjpDb2x1bW5NYWpvcjsKICAgIGNvbnN0ZXhwciBpbnQgQWxpZ25tZW50QiAgPSAzMjsKCiAgICB1c2luZyBFbGVtZW50RCA9IEVsZW1lbnRDOwogICAgdXNpbmcgTGF5b3V0QyAgPSBjdXRsYXNzOjpsYXlvdXQ6OlJvd01ham9yOwogICAgY29uc3RleHByIGludCBBbGlnbm1lbnRDICA9IDEyOCAvIGN1dGxhc3M6OnNpemVvZl9iaXRzPEVsZW1lbnRDPjo6dmFsdWU7CiAgICBjb25zdGV4cHIgaW50IEFsaWdubWVudEQgID0gMTI4IC8gY3V0bGFzczo6c2l6ZW9mX2JpdHM8RWxlbWVudEQ+Ojp2YWx1ZTsKICAgIHVzaW5nIEVsZW1lbnRBY2N1bXVsYXRvciAgPSBmbG9hdDsKCiAgICB1c2luZyBBcmNoVGFnID0gY3V0bGFzczo6YXJjaDo6U20xMDA7CiAgICB1c2luZyBPcGVyYXRvckNsYXNzID0gY3V0bGFzczo6YXJjaDo6T3BDbGFzc0Jsb2NrU2NhbGVkVGVuc29yT3A7CiAgICB1c2luZyBTdGFnZUNvdW50VHlwZSA9IGN1dGxhc3M6OmdlbW06OmNvbGxlY3RpdmU6OlN0YWdlQ291bnRBdXRvOwogICAgdXNpbmcgQ2x1c3RlclNoYXBlID0gY3V0ZTo6U2hhcGU8aW50MzJfdCxpbnQzMl90LGN1dGU6Ol8xPjsKCiAgICBzdHJ1Y3QgTU1BMVNNQ29uZmlnIHsKICAgICAgdXNpbmcgTW1hVGlsZVNoYXBlICAgICA9IGN1dGU6OlNoYXBlPGN1dGU6Ol8xMjgsY3V0ZTo6XzI1NixjdXRlOjpfMjU2PjsKICAgICAgdXNpbmcgS2VybmVsU2NoZWR1bGUgICA9IGN1dGxhc3M6OmdlbW06Oktlcm5lbFB0ckFycmF5VG1hV2FycFNwZWNpYWxpemVkMVNtTnZmNFNtMTAwOwogICAgICB1c2luZyBFcGlsb2d1ZVNjaGVkdWxlID0gY3V0bGFzczo6ZXBpbG9ndWU6OlB0ckFycmF5VG1hV2FycFNwZWNpYWxpemVkMVNtOwogICAgfTsKCiAgICBzdHJ1Y3QgTU1BMlNNQ29uZmlnIHsKICAgICAgdXNpbmcgTW1hVGlsZVNoYXBlICAgICA9IGN1dGU6OlNoYXBlPGN1dGU6Ol8yNTYsY3V0ZTo6XzI1NixjdXRlOjpfMjU2PjsKICAgICAgdXNpbmcgS2VybmVsU2NoZWR1bGUgICA9IGN1dGxhc3M6OmdlbW06Oktlcm5lbFB0ckFycmF5VG1hV2FycFNwZWNpYWxpemVkMlNtTnZmNFNtMTAwOwogICAgICB1c2luZyBFcGlsb2d1ZVNjaGVkdWxlID0gY3V0bGFzczo6ZXBpbG9ndWU6OlB0ckFycmF5VG1hV2FycFNwZWNpYWxpemVkMlNtOwogICAgfTsKCiAgICB1c2luZyBDb2xsZWN0aXZlRXBpbG9ndWUxU00gPSB0eXBlbmFtZSBjdXRsYXNzOjplcGlsb2d1ZTo6Y29sbGVjdGl2ZTo6Q29sbGVjdGl2ZUJ1aWxkZXI8CiAgICAgICAgQXJjaFRhZywgT3BlcmF0b3JDbGFzcywKICAgICAgICB0eXBlbmFtZSBNTUExU01Db25maWc6Ok1tYVRpbGVTaGFwZSwgQ2x1c3RlclNoYXBlLAogICAgICAgIGN1dGU6OlNoYXBlPGN1dGU6Ol8xMjgsY3V0ZTo6XzY0PiwKICAgICAgICBFbGVtZW50QWNjdW11bGF0b3IsIEVsZW1lbnRBY2N1bXVsYXRvciwKICAgICAgICBFbGVtZW50QywgTGF5b3V0QyAqLCBBbGlnbm1lbnRDLAogICAgICAgIEVsZW1lbnRELCBMYXlvdXRDICosIEFsaWdubWVudEQsCiAgICAgICAgdHlwZW5hbWUgTU1BMVNNQ29uZmlnOjpFcGlsb2d1ZVNjaGVkdWxlCiAgICA+OjpDb2xsZWN0aXZlT3A7CgogICAgdXNpbmcgQ29sbGVjdGl2ZU1haW5sb29wMVNNID0gdHlwZW5hbWUgY3V0bGFzczo6Z2VtbTo6Y29sbGVjdGl2ZTo6Q29sbGVjdGl2ZUJ1aWxkZXI8CiAgICAgIEFyY2hUYWcsIE9wZXJhdG9yQ2xhc3MsCiAgICAgIEVsZW1lbnRBLCBMYXlvdXRBICosIEFsaWdubWVudEEsCiAgICAgIEVsZW1lbnRCLCBMYXlvdXRCICosIEFsaWdubWVudEIsCiAgICAgIEVsZW1lbnRBY2N1bXVsYXRvciwKICAgICAgdHlwZW5hbWUgTU1BMVNNQ29uZmlnOjpNbWFUaWxlU2hhcGUsIENsdXN0ZXJTaGFwZSwKICAgICAgY3V0bGFzczo6Z2VtbTo6Y29sbGVjdGl2ZTo6U3RhZ2VDb3VudEF1dG9DYXJ2ZW91dDwKICAgICAgICBzdGF0aWNfY2FzdDxpbnQ+KHNpemVvZih0eXBlbmFtZSBDb2xsZWN0aXZlRXBpbG9ndWUxU006OlNoYXJlZFN0b3JhZ2UpKT4sCiAgICAgIHR5cGVuYW1lIE1NQTFTTUNvbmZpZzo6S2VybmVsU2NoZWR1bGUKICAgID46OkNvbGxlY3RpdmVPcDsKCiAgICB1c2luZyBHZW1tS2VybmVsMVNNID0gY3V0bGFzczo6Z2VtbTo6a2VybmVsOjpHZW1tVW5pdmVyc2FsPAogICAgICAgIFByb2JsZW1TaGFwZSwKICAgICAgICBDb2xsZWN0aXZlTWFpbmxvb3AxU00sCiAgICAgICAgQ29sbGVjdGl2ZUVwaWxvZ3VlMVNNCiAgICA+OwogICAgdXNpbmcgR2VtbTFTTSA9IGN1dGxhc3M6OmdlbW06OmRldmljZTo6R2VtbVVuaXZlcnNhbEFkYXB0ZXI8R2VtbUtlcm5lbDFTTT47CgogICAgdXNpbmcgQ29sbGVjdGl2ZUVwaWxvZ3VlMlNNID0gdHlwZW5hbWUgY3V0bGFzczo6ZXBpbG9ndWU6OmNvbGxlY3RpdmU6OkNvbGxlY3RpdmVCdWlsZGVyPAogICAgICAgIEFyY2hUYWcsIE9wZXJhdG9yQ2xhc3MsCiAgICAgICAgdHlwZW5hbWUgTU1BMlNNQ29uZmlnOjpNbWFUaWxlU2hhcGUsIENsdXN0ZXJTaGFwZSwKICAgICAgICBjdXRlOjpTaGFwZTxjdXRlOjpfMTI4LGN1dGU6Ol82ND4sCiAgICAgICAgRWxlbWVudEFjY3VtdWxhdG9yLCBFbGVtZW50QWNjdW11bGF0b3IsCiAgICAgICAgRWxlbWVudEMsIExheW91dEMgKiwgQWxpZ25tZW50QywKICAgICAgICBFbGVtZW50RCwgTGF5b3V0QyAqLCBBbGlnbm1lbnRELAogICAgICAgIHR5cGVuYW1lIE1NQTJTTUNvbmZpZzo6RXBpbG9ndWVTY2hlZHVsZQogICAgPjo6Q29sbGVjdGl2ZU9wOwoKICAgIHVzaW5nIENvbGxlY3RpdmVNYWlubG9vcDJTTSA9IHR5cGVuYW1lIGN1dGxhc3M6OmdlbW06OmNvbGxlY3RpdmU6OkNvbGxlY3RpdmVCdWlsZGVyPAogICAgICBBcmNoVGFnLCBPcGVyYXRvckNsYXNzLAogICAgICBFbGVtZW50QSwgTGF5b3V0QSAqLCBBbGlnbm1lbnRBLAogICAgICBFbGVtZW50QiwgTGF5b3V0QiAqLCBBbGlnbm1lbnRCLAogICAgICBFbGVtZW50QWNjdW11bGF0b3IsCiAgICAgIHR5cGVuYW1lIE1NQTJTTUNvbmZpZzo6TW1hVGlsZVNoYXBlLCBDbHVzdGVyU2hhcGUsCiAgICAgIGN1dGxhc3M6OmdlbW06OmNvbGxlY3RpdmU6OlN0YWdlQ291bnRBdXRvQ2FydmVvdXQ8CiAgICAgICAgc3RhdGljX2Nhc3Q8aW50PihzaXplb2YodHlwZW5hbWUgQ29sbGVjdGl2ZUVwaWxvZ3VlMlNNOjpTaGFyZWRTdG9yYWdlKSk+LAogICAgICB0eXBlbmFtZSBNTUEyU01Db25maWc6Oktlcm5lbFNjaGVkdWxlCiAgICA+OjpDb2xsZWN0aXZlT3A7CgogICAgdXNpbmcgR2VtbUtlcm5lbDJTTSA9IGN1dGxhc3M6OmdlbW06Omtlcm5lbDo6R2VtbVVuaXZlcnNhbDwKICAgICAgICBQcm9ibGVtU2hhcGUsCiAgICAgICAgQ29sbGVjdGl2ZU1haW5sb29wMlNNLAogICAgICAgIENvbGxlY3RpdmVFcGlsb2d1ZTJTTQogICAgPjsKICAgIHVzaW5nIEdlbW0yU00gPSBjdXRsYXNzOjpnZW1tOjpkZXZpY2U6OkdlbW1Vbml2ZXJzYWxBZGFwdGVyPEdlbW1LZXJuZWwyU00+OwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUPgogICAgc3RydWN0IFBpbm5lZEhvc3RCdWZmZXIgewogICAgICBUKiBwdHIgPSBudWxscHRyOwogICAgICBzaXplX3QgY291bnQgPSAwOwoKICAgICAgUGlubmVkSG9zdEJ1ZmZlcigpID0gZGVmYXVsdDsKICAgICAgZXhwbGljaXQgUGlubmVkSG9zdEJ1ZmZlcihzaXplX3QgbikgeyBhbGxvY2F0ZShuKTsgfQoKICAgICAgdm9pZCBhbGxvY2F0ZShzaXplX3QgbikgewogICAgICAgIGlmIChwdHIgJiYgY291bnQgPj0gbikgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICByZWxlYXNlKCk7CiAgICAgICAgY291bnQgPSBuOwogICAgICAgIENVREFfQ0hFQ0soY3VkYUhvc3RBbGxvYyhyZWludGVycHJldF9jYXN0PHZvaWQqKj4oJnB0ciksIG4gKiBzaXplb2YoVCksIGN1ZGFIb3N0QWxsb2NQb3J0YWJsZSkpOwogICAgICB9CgogICAgICB2b2lkIHJlbGVhc2UoKSB7CiAgICAgICAgaWYgKHB0cikgewogICAgICAgICAgY3VkYUZyZWVIb3N0KHB0cik7CiAgICAgICAgICBwdHIgPSBudWxscHRyOwogICAgICAgICAgY291bnQgPSAwOwogICAgICAgIH0KICAgICAgfQoKICAgICAgflBpbm5lZEhvc3RCdWZmZXIoKSB7IHJlbGVhc2UoKTsgfQoKICAgICAgVCogZGF0YSgpIGNvbnN0IHsgcmV0dXJuIHB0cjsgfQogICAgICBUJiBvcGVyYXRvcltdKHNpemVfdCBpZHgpIHsgcmV0dXJuIHB0cltpZHhdOyB9CiAgICB9OwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUPgogICAgc3RydWN0IERldmljZUJ1ZmZlciB7CiAgICAgIFQqIHB0ciA9IG51bGxwdHI7CiAgICAgIHNpemVfdCBjb3VudCA9IDA7CgogICAgICBEZXZpY2VCdWZmZXIoKSA9IGRlZmF1bHQ7CiAgICAgIGV4cGxpY2l0IERldmljZUJ1ZmZlcihzaXplX3QgbikgeyBhbGxvY2F0ZShuKTsgfQoKICAgICAgdm9pZCBhbGxvY2F0ZShzaXplX3QgbikgewogICAgICAgIGlmIChwdHIgJiYgY291bnQgPj0gbikgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICByZWxlYXNlKCk7CiAgICAgICAgY291bnQgPSBuOwogICAgICAgIENVREFfQ0hFQ0soY3VkYU1hbGxvYyhyZWludGVycHJldF9jYXN0PHZvaWQqKj4oJnB0ciksIG4gKiBzaXplb2YoVCkpKTsKICAgICAgfQoKICAgICAgdm9pZCByZWxlYXNlKCkgewogICAgICAgIGlmIChwdHIpIHsKICAgICAgICAgIGN1ZGFGcmVlKHB0cik7CiAgICAgICAgICBwdHIgPSBudWxscHRyOwogICAgICAgICAgY291bnQgPSAwOwogICAgICAgIH0KICAgICAgfQoKICAgICAgfkRldmljZUJ1ZmZlcigpIHsgcmVsZWFzZSgpOyB9CgogICAgICBUKiBnZXQoKSBjb25zdCB7IHJldHVybiBwdHI7IH0KCiAgICAgIHZvaWQgY29weV9mcm9tX2hvc3QoY29uc3QgVCogaG9zdCwgc2l6ZV90IG4sIGN1ZGFTdHJlYW1fdCBzdHJlYW0pIHsKICAgICAgICBDVURBX0NIRUNLKGN1ZGFNZW1jcHlBc3luYyhwdHIsIGhvc3QsIG4gKiBzaXplb2YoVCksIGN1ZGFNZW1jcHlIb3N0VG9EZXZpY2UsIHN0cmVhbSkpOwogICAgICB9CiAgICB9OwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBHZW1tPgogICAgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4gcnVuX2dyb3VwZWRfaW1wbCgKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgQSwKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgQiwKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgQywKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgU0ZBLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBTRkIpIHsKCiAgICAgIFRPUkNIX0NIRUNLKEEuc2l6ZSgpID09IEIuc2l6ZSgpLCAiQS9CIHNpemUgbWlzbWF0Y2giKTsKICAgICAgVE9SQ0hfQ0hFQ0soQS5zaXplKCkgPT0gQy5zaXplKCksICJBL0Mgc2l6ZSBtaXNtYXRjaCIpOwogICAgICBUT1JDSF9DSEVDSyhBLnNpemUoKSA9PSBTRkEuc2l6ZSgpLCAiQS9TRkEgc2l6ZSBtaXNtYXRjaCIpOwogICAgICBUT1JDSF9DSEVDSyhBLnNpemUoKSA9PSBTRkIuc2l6ZSgpLCAiQS9TRkIgc2l6ZSBtaXNtYXRjaCIpOwogICAgICBjb25zdCBpbnQzMl90IGdyb3VwcyA9IHN0YXRpY19jYXN0PGludDMyX3Q+KEEuc2l6ZSgpKTsKICAgICAgVE9SQ0hfQ0hFQ0soZ3JvdXBzID4gMCwgIk5vIGdyb3VwcyIpOwoKICAgICAgaW50IGRldmljZV9pZCA9IEFbMF0uZ2V0X2RldmljZSgpOwogICAgICBjMTA6OmN1ZGE6OkNVREFHdWFyZCBkZXZpY2VfZ3VhcmQoZGV2aWNlX2lkKTsKCiAgICAgIHVzaW5nIFN0cmlkZUEgPSB0eXBlbmFtZSBHZW1tOjpHZW1tS2VybmVsOjpJbnRlcm5hbFN0cmlkZUE7CiAgICAgIHVzaW5nIFN0cmlkZUIgPSB0eXBlbmFtZSBHZW1tOjpHZW1tS2VybmVsOjpJbnRlcm5hbFN0cmlkZUI7CiAgICAgIHVzaW5nIFN0cmlkZUMgPSB0eXBlbmFtZSBHZW1tOjpHZW1tS2VybmVsOjpJbnRlcm5hbFN0cmlkZUM7CiAgICAgIHVzaW5nIFN0cmlkZUQgPSB0eXBlbmFtZSBHZW1tOjpHZW1tS2VybmVsOjpJbnRlcm5hbFN0cmlkZUQ7CiAgICAgIHVzaW5nIExheW91dFNGQSA9IHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkNvbGxlY3RpdmVNYWlubG9vcDo6SW50ZXJuYWxMYXlvdXRTRkE7CiAgICAgIHVzaW5nIExheW91dFNGQiA9IHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkNvbGxlY3RpdmVNYWlubG9vcDo6SW50ZXJuYWxMYXlvdXRTRkI7CiAgICAgIHVzaW5nIFNtMXh4QmxrU2NhbGVkQ29uZmlnID0gdHlwZW5hbWUgR2VtbTo6R2VtbUtlcm5lbDo6Q29sbGVjdGl2ZU1haW5sb29wOjpTbTF4eEJsa1NjYWxlZENvbmZpZzsKCiAgICAgIHN0YXRpYyBzaXplX3QgY2FwYWNpdHkgPSAwOwogICAgICBzdGF0aWMgaW50IGNhY2hlZF9kZXZpY2UgPSAtMTsKICAgICAgc3RhdGljIFBpbm5lZEhvc3RCdWZmZXI8dHlwZW5hbWUgR2VtbTo6RWxlbWVudEEgY29uc3QqPiBwdHJfQV9ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjx0eXBlbmFtZSBHZW1tOjpFbGVtZW50QiBjb25zdCo+IHB0cl9CX2hvc3Q7CiAgICAgIHN0YXRpYyBQaW5uZWRIb3N0QnVmZmVyPHR5cGVuYW1lIEdlbW06OkVsZW1lbnRDIGNvbnN0Kj4gcHRyX0NfaG9zdDsKICAgICAgc3RhdGljIFBpbm5lZEhvc3RCdWZmZXI8dHlwZW5hbWUgR2VtbTo6RXBpbG9ndWVPdXRwdXRPcDo6RWxlbWVudE91dHB1dCo+IHB0cl9EX2hvc3Q7CiAgICAgIHN0YXRpYyBQaW5uZWRIb3N0QnVmZmVyPHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkVsZW1lbnRTRiBjb25zdCo+IHB0cl9TRkFfaG9zdDsKICAgICAgc3RhdGljIFBpbm5lZEhvc3RCdWZmZXI8dHlwZW5hbWUgR2VtbTo6R2VtbUtlcm5lbDo6RWxlbWVudFNGIGNvbnN0Kj4gcHRyX1NGQl9ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjxTdHJpZGVBPiBzdHJpZGVfQV9ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjxTdHJpZGVCPiBzdHJpZGVfQl9ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjxTdHJpZGVDPiBzdHJpZGVfQ19ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjxTdHJpZGVEPiBzdHJpZGVfRF9ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjxMYXlvdXRTRkE+IGxheW91dF9TRkFfaG9zdDsKICAgICAgc3RhdGljIFBpbm5lZEhvc3RCdWZmZXI8TGF5b3V0U0ZCPiBsYXlvdXRfU0ZCX2hvc3Q7CiAgICAgIHN0YXRpYyBQaW5uZWRIb3N0QnVmZmVyPHR5cGVuYW1lIFByb2JsZW1TaGFwZTo6VW5kZXJseWluZ1Byb2JsZW1TaGFwZT4gcHJvYmxlbV9zaXplc19ob3N0OwoKICAgICAgc3RhdGljIERldmljZUJ1ZmZlcjx0eXBlbmFtZSBQcm9ibGVtU2hhcGU6OlVuZGVybHlpbmdQcm9ibGVtU2hhcGU+IHByb2JsZW1fc2l6ZXNfZGV2aWNlOwogICAgICBzdGF0aWMgRGV2aWNlQnVmZmVyPHR5cGVuYW1lIEdlbW06OkVsZW1lbnRBIGNvbnN0Kj4gcHRyX0E7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8dHlwZW5hbWUgR2VtbTo6RWxlbWVudEIgY29uc3QqPiBwdHJfQjsKICAgICAgc3RhdGljIERldmljZUJ1ZmZlcjx0eXBlbmFtZSBHZW1tOjpHZW1tS2VybmVsOjpFbGVtZW50U0YgY29uc3QqPiBwdHJfU0ZBOwogICAgICBzdGF0aWMgRGV2aWNlQnVmZmVyPHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkVsZW1lbnRTRiBjb25zdCo+IHB0cl9TRkI7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8dHlwZW5hbWUgR2VtbTo6RWxlbWVudEMgY29uc3QqPiBwdHJfQzsKICAgICAgc3RhdGljIERldmljZUJ1ZmZlcjx0eXBlbmFtZSBHZW1tOjpFcGlsb2d1ZU91dHB1dE9wOjpFbGVtZW50T3V0cHV0Kj4gcHRyX0Q7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8U3RyaWRlQT4gc3RyaWRlX0E7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8U3RyaWRlQj4gc3RyaWRlX0I7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8U3RyaWRlQz4gc3RyaWRlX0M7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8U3RyaWRlRD4gc3RyaWRlX0Q7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8TGF5b3V0U0ZBPiBsYXlvdXRfU0ZBOwogICAgICBzdGF0aWMgRGV2aWNlQnVmZmVyPExheW91dFNGQj4gbGF5b3V0X1NGQjsKICAgICAgc3RhdGljIHNpemVfdCB3b3Jrc3BhY2Vfc2l6ZV9jYWNoZWQgPSAwOwogICAgICBzdGF0aWMgdG9yY2g6OlRlbnNvciB3b3Jrc3BhY2VfdGVuc29yOwoKICAgICAgaWYgKGNhY2hlZF9kZXZpY2UgIT0gZGV2aWNlX2lkIHx8IGNhcGFjaXR5IDwgc3RhdGljX2Nhc3Q8c2l6ZV90Pihncm91cHMpKSB7CiAgICAgICAgY2FjaGVkX2RldmljZSA9IGRldmljZV9pZDsKICAgICAgICBjYXBhY2l0eSA9IHN0YXRpY19jYXN0PHNpemVfdD4oZ3JvdXBzKTsKICAgICAgICBwdHJfQV9ob3N0LmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX0JfaG9zdC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHB0cl9DX2hvc3QuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBwdHJfRF9ob3N0LmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX1NGQV9ob3N0LmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX1NGQl9ob3N0LmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgc3RyaWRlX0FfaG9zdC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHN0cmlkZV9CX2hvc3QuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBzdHJpZGVfQ19ob3N0LmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgc3RyaWRlX0RfaG9zdC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIGxheW91dF9TRkFfaG9zdC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIGxheW91dF9TRkJfaG9zdC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHByb2JsZW1fc2l6ZXNfaG9zdC5hbGxvY2F0ZShncm91cHMpOwoKICAgICAgICBwcm9ibGVtX3NpemVzX2RldmljZS5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHB0cl9BLmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX0IuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBwdHJfU0ZBLmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX1NGQi5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHB0cl9DLmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX0QuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBzdHJpZGVfQS5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHN0cmlkZV9CLmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgc3RyaWRlX0MuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBzdHJpZGVfRC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIGxheW91dF9TRkEuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBsYXlvdXRfU0ZCLmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgIH0KCiAgICAgIGZvciAoaW50MzJfdCBpID0gMDsgaSA8IGdyb3VwczsgKytpKSB7CiAgICAgICAgVE9SQ0hfQ0hFQ0soQVtpXS5pc19jdWRhKCksICJBIG11c3QgYmUgQ1VEQSIpOwogICAgICAgIFRPUkNIX0NIRUNLKEJbaV0uaXNfY3VkYSgpLCAiQiBtdXN0IGJlIENVREEiKTsKICAgICAgICBUT1JDSF9DSEVDSyhDW2ldLmlzX2N1ZGEoKSwgIkMgbXVzdCBiZSBDVURBIik7CiAgICAgICAgVE9SQ0hfQ0hFQ0soU0ZBW2ldLmlzX2N1ZGEoKSwgIlNGQSBtdXN0IGJlIENVREEiKTsKICAgICAgICBUT1JDSF9DSEVDSyhTRkJbaV0uaXNfY3VkYSgpLCAiU0ZCIG11c3QgYmUgQ1VEQSIpOwoKICAgICAgICBpbnQzMl90IG0gPSBzdGF0aWNfY2FzdDxpbnQzMl90PihBW2ldLnNpemUoMCkpOwogICAgICAgIGludDMyX3Qga19wYWNrZWQgPSBzdGF0aWNfY2FzdDxpbnQzMl90PihBW2ldLnNpemUoMSkpOwogICAgICAgIGludDMyX3QgayA9IGtfcGFja2VkICogMjsKICAgICAgICBpbnQzMl90IG4gPSBzdGF0aWNfY2FzdDxpbnQzMl90PihCW2ldLnNpemUoMCkpOwogICAgICAgIFRPUkNIX0NIRUNLKEJbaV0uc2l6ZSgxKSAqIDIgPT0gaywgIksgbWlzbWF0Y2giKTsKICAgICAgICBUT1JDSF9DSEVDSyhDW2ldLnNpemUoMCkgPT0gbSAmJiBDW2ldLnNpemUoMSkgPT0gbiwgIkMgc2hhcGUgbWlzbWF0Y2giKTsKCiAgICAgICAgcHJvYmxlbV9zaXplc19ob3N0W2ldID0gY3V0ZTo6bWFrZV9zaGFwZShtLCBuLCBrKTsKICAgICAgICBzdHJpZGVfQV9ob3N0W2ldID0gY3V0bGFzczo6bWFrZV9jdXRlX3BhY2tlZF9zdHJpZGUoU3RyaWRlQXt9LCB7bSwgaywgMX0pOwogICAgICAgIHN0cmlkZV9CX2hvc3RbaV0gPSBjdXRsYXNzOjptYWtlX2N1dGVfcGFja2VkX3N0cmlkZShTdHJpZGVCe30sIHtuLCBrLCAxfSk7CiAgICAgICAgc3RyaWRlX0NfaG9zdFtpXSA9IGN1dGxhc3M6Om1ha2VfY3V0ZV9wYWNrZWRfc3RyaWRlKFN0cmlkZUN7fSwge20sIG4sIDF9KTsKICAgICAgICBzdHJpZGVfRF9ob3N0W2ldID0gY3V0bGFzczo6bWFrZV9jdXRlX3BhY2tlZF9zdHJpZGUoU3RyaWRlRHt9LCB7bSwgbiwgMX0pOwogICAgICAgIGxheW91dF9TRkFfaG9zdFtpXSA9IFNtMXh4QmxrU2NhbGVkQ29uZmlnOjp0aWxlX2F0b21fdG9fc2hhcGVfU0ZBKGN1dGU6Om1ha2Vfc2hhcGUobSwgbiwgaywgMSkpOwogICAgICAgIGxheW91dF9TRkJfaG9zdFtpXSA9IFNtMXh4QmxrU2NhbGVkQ29uZmlnOjp0aWxlX2F0b21fdG9fc2hhcGVfU0ZCKGN1dGU6Om1ha2Vfc2hhcGUobSwgbiwgaywgMSkpOwoKICAgICAgICBwdHJfQV9ob3N0W2ldID0gcmVpbnRlcnByZXRfY2FzdDx0eXBlbmFtZSBHZW1tOjpFbGVtZW50QSBjb25zdCo+KEFbaV0uZGF0YV9wdHIoKSk7CiAgICAgICAgcHRyX0JfaG9zdFtpXSA9IHJlaW50ZXJwcmV0X2Nhc3Q8dHlwZW5hbWUgR2VtbTo6RWxlbWVudEIgY29uc3QqPihCW2ldLmRhdGFfcHRyKCkpOwogICAgICAgIHB0cl9DX2hvc3RbaV0gPSByZWludGVycHJldF9jYXN0PHR5cGVuYW1lIEdlbW06OkVsZW1lbnRDIGNvbnN0Kj4oQ1tpXS5kYXRhX3B0cigpKTsKICAgICAgICBwdHJfRF9ob3N0W2ldID0gcmVpbnRlcnByZXRfY2FzdDx0eXBlbmFtZSBHZW1tOjpFcGlsb2d1ZU91dHB1dE9wOjpFbGVtZW50T3V0cHV0Kj4oQ1tpXS5kYXRhX3B0cigpKTsKICAgICAgICBwdHJfU0ZBX2hvc3RbaV0gPSByZWludGVycHJldF9jYXN0PHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkVsZW1lbnRTRiBjb25zdCo+KFNGQVtpXS5kYXRhX3B0cigpKTsKICAgICAgICBwdHJfU0ZCX2hvc3RbaV0gPSByZWludGVycHJldF9jYXN0PHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkVsZW1lbnRTRiBjb25zdCo+KFNGQltpXS5kYXRhX3B0cigpKTsKICAgICAgfQoKICAgICAgYXV0byBzdHJlYW1fb2JqID0gYzEwOjpjdWRhOjpnZXRDdXJyZW50Q1VEQVN0cmVhbShkZXZpY2VfaWQpOwogICAgICBjMTA6OmN1ZGE6OkNVREFTdHJlYW1HdWFyZCBzdHJlYW1fZ3VhcmQoc3RyZWFtX29iaik7CiAgICAgIGN1ZGFTdHJlYW1fdCBzdHJlYW0gPSBzdHJlYW1fb2JqLnN0cmVhbSgpOwogICAgICBwcm9ibGVtX3NpemVzX2RldmljZS5jb3B5X2Zyb21faG9zdChwcm9ibGVtX3NpemVzX2hvc3QuZGF0YSgpLCBncm91cHMsIHN0cmVhbSk7CiAgICAgIHB0cl9BLmNvcHlfZnJvbV9ob3N0KHB0cl9BX2hvc3QuZGF0YSgpLCBncm91cHMsIHN0cmVhbSk7CiAgICAgIHB0cl9CLmNvcHlfZnJvbV9ob3N0KHB0cl9CX2hvc3QuZGF0YSgpLCBncm91cHMsIHN0cmVhbSk7CiAgICAgIHB0cl9TRkEuY29weV9mcm9tX2hvc3QocHRyX1NGQV9ob3N0LmRhdGEoKSwgZ3JvdXBzLCBzdHJlYW0pOwogICAgICBwdHJfU0ZCLmNvcHlfZnJvbV9ob3N0KHB0cl9TRkJfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgcHRyX0MuY29weV9mcm9tX2hvc3QocHRyX0NfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgcHRyX0QuY29weV9mcm9tX2hvc3QocHRyX0RfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgc3RyaWRlX0EuY29weV9mcm9tX2hvc3Qoc3RyaWRlX0FfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgc3RyaWRlX0IuY29weV9mcm9tX2hvc3Qoc3RyaWRlX0JfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgc3RyaWRlX0MuY29weV9mcm9tX2hvc3Qoc3RyaWRlX0NfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgc3RyaWRlX0QuY29weV9mcm9tX2hvc3Qoc3RyaWRlX0RfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgbGF5b3V0X1NGQS5jb3B5X2Zyb21faG9zdChsYXlvdXRfU0ZBX2hvc3QuZGF0YSgpLCBncm91cHMsIHN0cmVhbSk7CiAgICAgIGxheW91dF9TRkIuY29weV9mcm9tX2hvc3QobGF5b3V0X1NGQl9ob3N0LmRhdGEoKSwgZ3JvdXBzLCBzdHJlYW0pOwoKICAgICAgY3V0bGFzczo6S2VybmVsSGFyZHdhcmVJbmZvIGh3X2luZm87CiAgICAgIGh3X2luZm8uZGV2aWNlX2lkID0gZGV2aWNlX2lkOwogICAgICBod19pbmZvLnNtX2NvdW50ID0gY3V0bGFzczo6S2VybmVsSGFyZHdhcmVJbmZvOjpxdWVyeV9kZXZpY2VfbXVsdGlwcm9jZXNzb3JfY291bnQoaHdfaW5mby5kZXZpY2VfaWQpOwogICAgICBpZiBjb25zdGV4cHIgKHN0ZDo6aXNfc2FtZV92PEdlbW0sIEdlbW0xU00+KSB7CiAgICAgICAgaHdfaW5mby5jbHVzdGVyX3NoYXBlID0gZGltMygxLCAxLCAxKTsKICAgICAgICBod19pbmZvLmNsdXN0ZXJfc2hhcGVfZmFsbGJhY2sgPSBkaW0zKDEsIDEsIDEpOwogICAgICB9IGVsc2UgewogICAgICAgIGh3X2luZm8uY2x1c3Rlcl9zaGFwZSA9IGRpbTMoMiwgMSwgMSk7CiAgICAgICAgaHdfaW5mby5jbHVzdGVyX3NoYXBlX2ZhbGxiYWNrID0gZGltMygyLCAxLCAxKTsKICAgICAgfQoKICAgICAgdHlwZW5hbWUgR2VtbTo6QXJndW1lbnRzIGFyZ3VtZW50czsKICAgICAgZGVjbHR5cGUoYXJndW1lbnRzLmVwaWxvZ3VlLnRocmVhZCkgZnVzaW9uX2FyZ3M7CiAgICAgIGZ1c2lvbl9hcmdzLmFscGhhX3B0ciA9IG51bGxwdHI7CiAgICAgIGZ1c2lvbl9hcmdzLmJldGFfcHRyID0gbnVsbHB0cjsKICAgICAgZnVzaW9uX2FyZ3MuYWxwaGEgPSBFbGVtZW50QWNjdW11bGF0b3IoMSk7CiAgICAgIGZ1c2lvbl9hcmdzLmJldGEgPSBFbGVtZW50QWNjdW11bGF0b3IoMCk7CiAgICAgIGZ1c2lvbl9hcmdzLmFscGhhX3B0cl9hcnJheSA9IG51bGxwdHI7CiAgICAgIGZ1c2lvbl9hcmdzLmJldGFfcHRyX2FycmF5ID0gbnVsbHB0cjsKICAgICAgZnVzaW9uX2FyZ3MuZEFscGhhID0ge2N1dGU6Ol8we30sIGN1dGU6Ol8we30sIDB9OwogICAgICBmdXNpb25fYXJncy5kQmV0YSA9IHtjdXRlOjpfMHt9LCBjdXRlOjpfMHt9LCAwfTsKCiAgICAgIHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OlRpbGVTY2hlZHVsZXJBcmd1bWVudHMgc2NoZWR1bGVyOwogICAgICBzY2hlZHVsZXIubWF4X3N3aXp6bGVfc2l6ZSA9IDg7CiAgICAgIHNjaGVkdWxlci5yYXN0ZXJfb3JkZXIgPSBjdXRsYXNzOjpnZW1tOjprZXJuZWw6OmRldGFpbDo6UmFzdGVyT3JkZXJPcHRpb25zOjpBbG9uZ047CgogICAgICBhcmd1bWVudHMgPSB0eXBlbmFtZSBHZW1tOjpBcmd1bWVudHMgewogICAgICAgIGN1dGxhc3M6OmdlbW06OkdlbW1Vbml2ZXJzYWxNb2RlOjprR3JvdXBlZCwKICAgICAgICB7Z3JvdXBzLCBwcm9ibGVtX3NpemVzX2RldmljZS5nZXQoKSwgcHJvYmxlbV9zaXplc19ob3N0LmRhdGEoKX0sCiAgICAgICAge3B0cl9BLmdldCgpLCBzdHJpZGVfQS5nZXQoKSwgcHRyX0IuZ2V0KCksIHN0cmlkZV9CLmdldCgpLAogICAgICAgICBwdHJfU0ZBLmdldCgpLCBsYXlvdXRfU0ZBLmdldCgpLCBwdHJfU0ZCLmdldCgpLCBsYXlvdXRfU0ZCLmdldCgpfSwKICAgICAgICB7ZnVzaW9uX2FyZ3MsIHB0cl9DLmdldCgpLCBzdHJpZGVfQy5nZXQoKSwgcHRyX0QuZ2V0KCksIHN0cmlkZV9ELmdldCgpfSwKICAgICAgICBod19pbmZvLCBzY2hlZHVsZXIKICAgICAgfTsKCiAgICAgIEdlbW0gZ2VtbTsKICAgICAgc2l6ZV90IHdvcmtzcGFjZV9zaXplID0gR2VtbTo6Z2V0X3dvcmtzcGFjZV9zaXplKGFyZ3VtZW50cyk7CiAgICAgIGlmICghd29ya3NwYWNlX3RlbnNvci5kZWZpbmVkKCkgfHwgY2FjaGVkX2RldmljZSAhPSBkZXZpY2VfaWQgfHwgd29ya3NwYWNlX3NpemVfY2FjaGVkIDwgd29ya3NwYWNlX3NpemUpIHsKICAgICAgICBhdXRvIG9wdHMgPSB0b3JjaDo6VGVuc29yT3B0aW9ucygpLmRldmljZSh0b3JjaDo6a0NVREEsIGRldmljZV9pZCkuZHR5cGUodG9yY2g6OmtVSW50OCk7CiAgICAgICAgd29ya3NwYWNlX3RlbnNvciA9IHRvcmNoOjplbXB0eSh7c3RhdGljX2Nhc3Q8bG9uZz4od29ya3NwYWNlX3NpemUpfSwgb3B0cyk7CiAgICAgICAgd29ya3NwYWNlX3NpemVfY2FjaGVkID0gd29ya3NwYWNlX3NpemU7CiAgICAgIH0KICAgICAgdm9pZCogd29ya3NwYWNlX3B0ciA9IHdvcmtzcGFjZV9zaXplID8gd29ya3NwYWNlX3RlbnNvci5kYXRhX3B0cigpIDogbnVsbHB0cjsKCiAgICAgIENVVExBU1NfQ0hFQ0soZ2VtbS5jYW5faW1wbGVtZW50KGFyZ3VtZW50cykpOwogICAgICBDVVRMQVNTX0NIRUNLKGdlbW0uaW5pdGlhbGl6ZShhcmd1bWVudHMsIHdvcmtzcGFjZV9wdHIsIHN0cmVhbSkpOwogICAgICBhdXRvIHJ1bl9zdGF0dXMgPSBnZW1tLnJ1bihzdHJlYW0sIG51bGxwdHIsIHRydWUpOwogICAgICBpZiAocnVuX3N0YXR1cyAhPSBjdXRsYXNzOjpTdGF0dXM6OmtTdWNjZXNzKSB7CiAgICAgICAgcnVuX3N0YXR1cyA9IGdlbW0ucnVuKHN0cmVhbSk7CiAgICAgIH0KICAgICAgQ1VUTEFTU19DSEVDSyhydW5fc3RhdHVzKTsKCiAgICAgIHJldHVybiBDOwogICAgfQoKICAgIHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+IGdyb3VwZWRfZ2VtbV8xc20oCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIEEsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIEIsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIEMsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIFNGQSwKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgU0ZCKSB7CiAgICAgIHJldHVybiBydW5fZ3JvdXBlZF9pbXBsPEdlbW0xU00+KEEsIEIsIEMsIFNGQSwgU0ZCKTsKICAgIH0KCiAgICBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiBncm91cGVkX2dlbW1fMnNtKAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBBLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBCLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBDLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBTRkEsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIFNGQikgewogICAgICByZXR1cm4gcnVuX2dyb3VwZWRfaW1wbDxHZW1tMlNNPihBLCBCLCBDLCBTRkEsIFNGQik7CiAgICB9CiAgICAK"
_ext_mod = None
_ext_fail = False
_force_ext_only = False
_disable_ext = False
def _dec(b64: str) -> str:
return base64.b64decode(b64).decode("utf-8")
def _find_inc() -> list[str]:
incs: list[str] = []
def _add_cutlass(base: str) -> bool:
inc = os.path.join(base, "include")
if os.path.isfile(os.path.join(inc, "cutlass", "cutlass.h")):
incs.append(inc)
util_inc = os.path.join(base, "tools", "util", "include")
if os.path.isfile(os.path.join(util_inc, "cutlass", "util", "device_memory.h")):
incs.append(util_inc)
return True
inc2 = os.path.join(base, "cutlass", "include")
if os.path.isfile(os.path.join(inc2, "cutlass", "cutlass.h")):
incs.append(inc2)
util_inc2 = os.path.join(base, "cutlass", "tools", "util", "include")
if os.path.isfile(os.path.join(util_inc2, "cutlass", "util", "device_memory.h")):
incs.append(util_inc2)
return True
return False
here = os.path.abspath(os.path.dirname(__file__))
repo_root = os.path.abspath(os.path.join(here, "../../../.."))
for base in (
os.path.join(repo_root, "third_party", "cutlass"),
os.path.join(repo_root, "tmp", "cutlass-4.3.5"),
):
_add_cutlass(base)
try:
import cutlass as _c
root = os.path.dirname(getattr(_c, "__file__", "") or "")
if root:
bases = [root, os.path.dirname(root), os.path.dirname(os.path.dirname(root))]
for base in bases:
if _add_cutlass(base):
break
except Exception:
pass
try:
import torch.utils.cpp_extension as _ce
for inc in _ce.include_paths():
if os.path.isfile(os.path.join(inc, "cutlass", "cutlass.h")):
incs.append(inc)
util_inc3 = os.path.join(inc, "cutlass", "tools", "util", "include")
if os.path.isfile(os.path.join(util_inc3, "cutlass", "util", "device_memory.h")):
incs.append(util_inc3)
except Exception:
pass
if not incs:
root = _ensure_cutlass_dir()
if root:
_add_cutlass(root)
return incs
_cutlass_root_cached: str | None = None
def _ensure_cutlass_dir() -> str | None:
global _cutlass_root_cached
if _cutlass_root_cached is not None:
return _cutlass_root_cached
base_dir = "/tmp/cutlass_cache"
root = os.path.join(base_dir, "cutlass-4.3.5")
inc = os.path.join(root, "include", "cutlass", "cutlass.h")
if os.path.isfile(inc):
_cutlass_root_cached = root
return root
try:
os.makedirs(base_dir, exist_ok=True)
tgz_path = os.path.join(base_dir, "cutlass.tgz")
if not os.path.isfile(tgz_path):
import urllib.request
url = "https://github.com/NVIDIA/cutlass/archive/refs/tags/v4.3.5.tar.gz"
with urllib.request.urlopen(url, timeout=60) as resp:
data = resp.read()
with open(tgz_path, "wb") as f:
f.write(data)
import tarfile
with tarfile.open(tgz_path, "r:gz") as tf:
tf.extractall(base_dir)
if os.path.isfile(inc):
_cutlass_root_cached = root
return root
except Exception:
return None
return None
def _load_ext():
global _ext_mod, _ext_fail
if _ext_mod is not None or _ext_fail:
return _ext_mod
incs = _find_inc()
if not incs:
_ext_fail = True
if _force_ext_only:
raise RuntimeError("ext include paths not found")
return None
try:
from torch.utils.cpp_extension import load_inline
here = os.path.abspath(os.path.dirname(__file__))
repo_root = os.path.abspath(os.path.join(here, "../../../.."))
os.environ.setdefault(
"TORCH_EXTENSIONS_DIR", os.path.join(repo_root, "tmp", "torch_extensions")
)
os.environ.setdefault("TORCH_CUDA_ARCH_LIST", "10.0a")
cpp_src = _dec(_CPP_B64)
cu_src = _dec(_CU_B64)
_ext_mod = load_inline(
name="nvfp4_grouped_cutlass_ext_m128",
cpp_sources=cpp_src,
cuda_sources=cu_src,
functions=["grouped_gemm_1sm", "grouped_gemm_2sm"],
extra_cuda_cflags=[
"-O3",
"--use_fast_math",
"-std=c++17",
"--diag-suppress=144",
],
extra_ldflags=["-lcuda"],
extra_cflags=["-O3", "-std=c++17"],
with_cuda=True,
extra_include_paths=incs,
verbose=False,
)
except Exception as exc:
_ext_fail = True
_ext_mod = None
if _force_ext_only:
raise RuntimeError(f"ext build failed: {exc}") from exc
return _ext_mod
def _try_ext(
abc_tensors: list[tuple[torch.Tensor, torch.Tensor, torch.Tensor]],
sfasfb_reordered_tensors: list[tuple[torch.Tensor, torch.Tensor]],
problem_sizes: list[tuple[int, int, int, int]],
):
if _disable_ext:
return None
ext = _load_ext()
if ext is None:
return None
items = []
for (a_ref, b_ref, c_ref), (sfa_reordered, sfb_reordered), (m, _, k, l) in zip(
abc_tensors, sfasfb_reordered_tensors, problem_sizes
):
if l != 1:
return None
a2 = a_ref[:, :, 0]
b2 = b_ref[:, :, 0]
c2 = c_ref[:, :, 0]
items.append((a2, b2, c2, sfa_reordered, sfb_reordered, m, k))
def _use_2sm(m: int, k: int) -> bool:
return m >= 128 and k >= 2048
def _gather(src):
return (
[x[0] for x in src],
[x[1] for x in src],
[x[2] for x in src],
[x[3] for x in src],
[x[4] for x in src],
)
small = [it for it in items if not _use_2sm(it[5], it[6])]
large = [it for it in items if _use_2sm(it[5], it[6])]
try:
if large:
a_list, b_list, c_list, sfa_list, sfb_list = _gather(large)
ext.grouped_gemm_2sm(a_list, b_list, c_list, sfa_list, sfb_list)
if small:
a_list, b_list, c_list, sfa_list, sfb_list = _gather(small)
ext.grouped_gemm_1sm(a_list, b_list, c_list, sfa_list, sfb_list)
except Exception:
try:
a_list, b_list, c_list, sfa_list, sfb_list = _gather(items)
ext.grouped_gemm_1sm(a_list, b_list, c_list, sfa_list, sfb_list)
except Exception:
return None
return [c_ref for (_, _, c_ref) in abc_tensors]
_scale_cache: dict[tuple[int, int], torch.Tensor] = {}
_scaled_mm_out_supported: bool | None = None
_scaled_mm_fast_accum_supported: bool | None = None
_grouped_mm_v2_supported: bool | None = False
_grouped_mm_supported: bool | None = None
_group_cache: dict[tuple, dict] = {}
_group_cache_padded: dict[tuple, dict] = {}
_grouped_strategy_cache: dict[tuple, str] = {}
_grouped_strategy_cache_v1: dict[tuple, str] = {}
_scale_recipe_cached = None
_global_scale_recipe_cached = None
_swizzle_cached = None
_global_swizzle_cached = None
_global_scale_cache: dict[tuple[int, int, int], torch.Tensor] = {}
_dbg_on = False
_dbg_once = False
def _dbg(msg: str) -> None:
global _dbg_once
if _dbg_on and not _dbg_once:
print(msg)
_dbg_once = True
def blocked_from_reordered(sf_reordered: torch.Tensor, l_idx: int) -> torch.Tensor:
key = (sf_reordered.data_ptr(), l_idx)
cached = _scale_cache.get(key)
if cached is not None:
return cached
perm = sf_reordered.permute(2, 4, 0, 1, 3, 5)
flat = perm.reshape(-1, 32, 16, sf_reordered.shape[-1])[..., l_idx].reshape(-1)
flat = flat.contiguous()
_scale_cache[key] = flat
return flat
def _round_up(x: int, m: int) -> int:
return (x + m - 1) // m * m
def _get_grouped_mm_v2():
global _grouped_mm_v2_supported
if _grouped_mm_v2_supported is None:
try:
_ = torch.nn.functional.scaled_grouped_mm
_grouped_mm_v2_supported = True
except Exception:
_grouped_mm_v2_supported = False
return None
if _grouped_mm_v2_supported:
return torch.nn.functional.scaled_grouped_mm
return None
def _get_grouped_mm():
global _grouped_mm_supported
if _grouped_mm_supported is None:
try:
_grouped_mm_supported = True
return torch.ops.aten._scaled_grouped_mm
except Exception:
_grouped_mm_supported = False
return None
if _grouped_mm_supported:
return torch.ops.aten._scaled_grouped_mm
return None
def _find_enum_value(enum_obj, target: str):
key = target.replace("_", "").upper()
for attr in dir(enum_obj):
if attr.startswith("_"):
continue
attr_key = attr.replace("_", "").upper()
if attr_key == key:
return getattr(enum_obj, attr)
return None
def _get_scale_swizzle():
global _scale_recipe_cached, _swizzle_cached
global _global_scale_recipe_cached, _global_swizzle_cached
if _scale_recipe_cached is not None and _swizzle_cached is not None:
return (
_scale_recipe_cached,
_global_scale_recipe_cached,
_swizzle_cached,
_global_swizzle_cached,
)
try:
scaling_type = torch.nn.functional.ScalingType
swizzle_type = torch.nn.functional.SwizzleType
except Exception:
return None, None, None, None
block_scale = _find_enum_value(scaling_type, "BLOCKWISE_16")
global_scale = _find_enum_value(scaling_type, "TENSORWISE")
if global_scale is None:
global_scale = _find_enum_value(scaling_type, "TENSOR_WISE")
if global_scale is None:
global_scale = _find_enum_value(scaling_type, "TENSOR")
block_swizzle = _find_enum_value(swizzle_type, "SWIZZLE_32_4_4")
global_swizzle = _find_enum_value(swizzle_type, "NONE")
_scale_recipe_cached = block_scale
_global_scale_recipe_cached = global_scale
_swizzle_cached = block_swizzle
_global_swizzle_cached = global_swizzle
return block_scale, global_scale, block_swizzle, global_swizzle
def _get_global_scale(num_groups: int, device: torch.device, per_group: bool) -> torch.Tensor:
key = (
device.index if device.type == "cuda" else -1,
num_groups if per_group else 1,
1 if per_group else 0,
)
cached = _global_scale_cache.get(key)
if cached is not None and cached.device == device:
return cached
shape = (num_groups, 1) if per_group else (1,)
scale = torch.ones(shape, device=device, dtype=torch.float32)
_global_scale_cache[key] = scale
return scale
def _build_grouped_inputs(
abc_tensors, sfasfb_reordered_tensors, problem_sizes
) -> dict:
key = []
for (a_ref, b_ref, _), (sfa_reordered, sfb_reordered) in zip(
abc_tensors, sfasfb_reordered_tensors
):
key.append(
(
a_ref.data_ptr(),
b_ref.data_ptr(),
sfa_reordered.data_ptr(),
sfb_reordered.data_ptr(),
a_ref.shape,
b_ref.shape,
)
)
key = tuple(key)
cached = _group_cache.get(key)
if cached is not None:
return cached
a_blocks = []
b_blocks = []
scale_a_blocks = []
scale_b_blocks = []
offs = []
m_pads = []
m_actual = []
offset = 0
for (a_ref, b_ref, _), (sfa_reordered, sfb_reordered), (m, _, _, l) in zip(
abc_tensors, sfasfb_reordered_tensors, problem_sizes
):
if l != 1:
raise RuntimeError("grouped path only supports l=1")
m_pad = _round_up(m, 128)
m_pads.append(m_pad)
m_actual.append(m)
if m_pad == m:
a_pad = a_ref[:, :, 0]
else:
a_pad = torch.zeros(
(m_pad, a_ref.shape[1]), device=a_ref.device, dtype=a_ref.dtype
)
a_pad[:m].copy_(a_ref[:, :, 0])
a_blocks.append(a_pad)
b_blocks.append(b_ref[:, :, 0])
scale_a_blocks.append(blocked_from_reordered(sfa_reordered, 0))
scale_b_blocks.append(blocked_from_reordered(sfb_reordered, 0))
offset += m_pad
offs.append(offset)
m_pad_max = max(m_pads) if m_pads else 0
k_val = problem_sizes[0][2] if problem_sizes else 0
k_blocks = _round_up((k_val + 15) // 16, 4)
scale_len_pad = m_pad_max * k_blocks
scale_a_stack = []
for scale_a in scale_a_blocks:
if scale_a.numel() < scale_len_pad:
pad_len = scale_len_pad - scale_a.numel()
scale_a = torch.cat(
[
scale_a,
torch.zeros((pad_len,), device=scale_a.device, dtype=scale_a.dtype),
],
dim=0,
)
scale_a_stack.append(scale_a)
if scale_a_stack:
scale_a_stack = torch.stack(scale_a_stack, dim=0)
a_concat = torch.cat(a_blocks, dim=0)
b_nk = torch.stack(b_blocks, dim=0)
b_kn = b_nk.transpose(1, 2).contiguous()
scale_a = torch.cat(scale_a_blocks, dim=0)
scale_b = torch.stack(scale_b_blocks, dim=0)
offs_cpu = torch.tensor(offs, dtype=torch.int32)
offs_tensor = offs_cpu.to(device=a_concat.device)
packed = {
"a": a_concat,
"b_nk": b_nk,
"b_kn": b_kn,
"scale_a": scale_a,
"scale_a_stack": scale_a_stack,
"scale_b": scale_b,
"offs": offs_tensor,
"offs_cpu": offs_cpu,
"m_pads": m_pads,
"m_actual": m_actual,
}
_group_cache[key] = packed
return packed
def _build_grouped_inputs_padded(
abc_tensors, sfasfb_reordered_tensors, problem_sizes
) -> dict:
key = []
for (a_ref, b_ref, _), (sfa_reordered, sfb_reordered) in zip(
abc_tensors, sfasfb_reordered_tensors
):
key.append(
(
a_ref.data_ptr(),
b_ref.data_ptr(),
sfa_reordered.data_ptr(),
sfb_reordered.data_ptr(),
a_ref.shape,
b_ref.shape,
)
)
key = tuple(key)
cached = _group_cache_padded.get(key)
if cached is not None:
return cached
ms = [m for (m, _, _, _) in problem_sizes]
m_pad = _round_up(max(ms), 128) if ms else 0
k_val = problem_sizes[0][2] if problem_sizes else 0
k_blocks = _round_up((k_val + 15) // 16, 4)
scale_len_pad = m_pad * k_blocks
a_blocks = []
b_blocks = []
scale_a_blocks = []
scale_b_blocks = []
m_actual = []
for (a_ref, b_ref, _), (sfa_reordered, sfb_reordered), (m, _, _, l) in zip(
abc_tensors, sfasfb_reordered_tensors, problem_sizes
):
if l != 1:
raise RuntimeError("grouped path only supports l=1")
m_actual.append(m)
a_pad = torch.zeros(
(m_pad, a_ref.shape[1]), device=a_ref.device, dtype=a_ref.dtype
)
a_pad[:m].copy_(a_ref[:, :, 0])
a_blocks.append(a_pad)
b_blocks.append(b_ref[:, :, 0])
scale_a = blocked_from_reordered(sfa_reordered, 0)
if scale_a.numel() < scale_len_pad:
pad_len = scale_len_pad - scale_a.numel()
scale_a = torch.cat(
[
scale_a,
torch.zeros((pad_len,), device=scale_a.device, dtype=scale_a.dtype),
],
dim=0,
)
scale_a_blocks.append(scale_a)
scale_b_blocks.append(blocked_from_reordered(sfb_reordered, 0))
a_stack = torch.stack(a_blocks, dim=0) if a_blocks else None
b_nk = torch.stack(b_blocks, dim=0) if b_blocks else None
b_kn = b_nk.transpose(1, 2).contiguous() if b_nk is not None else None
scale_a = torch.stack(scale_a_blocks, dim=0) if scale_a_blocks else None
scale_b = torch.stack(scale_b_blocks, dim=0) if scale_b_blocks else None
packed = {
"a": a_stack,
"b_nk": b_nk,
"b_kn": b_kn,
"scale_a": scale_a,
"scale_b": scale_b,
"m_actual": m_actual,
"m_pad": m_pad,
}
_group_cache_padded[key] = packed
return packed
def _try_scaled_grouped_mm_v2(
func,
a,
b,
scale_a,
scale_recipe_a,
scale_b,
scale_recipe_b,
swizzle_a,
swizzle_b,
offs,
offs_cpu,
output_dtype,
):
for offs_arg in (offs, offs_cpu):
try:
return func(
a,
b,
scale_a,
scale_recipe_a,
scale_b,
scale_recipe_b,
swizzle_a=swizzle_a,
swizzle_b=swizzle_b,
bias=None,
offs=offs_arg,
output_dtype=output_dtype,
contraction_dim=(),
use_fast_accum=False,
)
except TypeError:
try:
return func(
a,
b,
scale_a,
scale_recipe_a,
scale_b,
scale_recipe_b,
swizzle_a=swizzle_a,
swizzle_b=swizzle_b,
bias=None,
offs=offs_arg,
output_dtype=output_dtype,
)
except Exception:
continue
except Exception:
continue
return None
def _try_scaled_grouped_mm_v1(
func,
a,
b,
scale_a,
scale_b,
offs,
offs_cpu,
output_dtype,
):
for offs_arg in (offs, offs_cpu):
try:
return func(
a,
b,
scale_a,
scale_b,
offs_arg,
None,
None,
output_dtype,
False,
)
except Exception:
continue
return None
def _scaled_mm_out(mat_a, mat_b, scale_a, scale_b, out_tensor):
global _scaled_mm_out_supported, _scaled_mm_fast_accum_supported
if _scaled_mm_out_supported is None:
try:
torch._scaled_mm(
mat_a,
mat_b,
scale_a,
scale_b,
bias=None,
out_dtype=torch.float16,
use_fast_accum=True,
out=out_tensor,
)
_scaled_mm_out_supported = True
_scaled_mm_fast_accum_supported = True
return out_tensor
except Exception:
try:
torch._scaled_mm(
mat_a,
mat_b,
scale_a,
scale_b,
bias=None,
out_dtype=torch.float16,
out=out_tensor,
)
_scaled_mm_out_supported = True
_scaled_mm_fast_accum_supported = False
return out_tensor
except Exception:
_scaled_mm_out_supported = False
if _scaled_mm_out_supported:
if _scaled_mm_fast_accum_supported:
torch._scaled_mm(
mat_a,
mat_b,
scale_a,
scale_b,
bias=None,
out_dtype=torch.float16,
use_fast_accum=True,
out=out_tensor,
)
else:
torch._scaled_mm(
mat_a,
mat_b,
scale_a,
scale_b,
bias=None,
out_dtype=torch.float16,
out=out_tensor,
)
return out_tensor
if _scaled_mm_fast_accum_supported:
out = torch._scaled_mm(
mat_a,
mat_b,
scale_a,
scale_b,
bias=None,
out_dtype=torch.float16,
use_fast_accum=True,
)
else:
out = torch._scaled_mm(
mat_a,
mat_b,
scale_a,
scale_b,
bias=None,
out_dtype=torch.float16,
)
out_tensor.copy_(out)
return out_tensor
def custom_kernel(data: input_t) -> output_t:
abc_tensors, _, sfasfb_reordered_tensors, problem_sizes = data
if _dbg_on:
try:
doc = getattr(torch.nn.functional.scaled_grouped_mm, "__doc__", None)
if doc:
_dbg("v2doc:" + doc[:600].replace("\n", " "))
else:
_dbg("v2doc:none")
except Exception as exc:
_dbg("v2docerr:" + str(exc))
try:
_dbg("v1op:" + str(torch.ops.aten._scaled_grouped_mm))
except Exception as exc:
_dbg("v1operr:" + str(exc))
ext_res = _try_ext(abc_tensors, sfasfb_reordered_tensors, problem_sizes)
if ext_res is not None:
return ext_res
if _force_ext_only:
raise RuntimeError("ext path failed")
result_tensors = []
def _emit_from_2d(out, grouped):
local_results = []
offset = 0
for (_, _, c_ref), m_pad, m in zip(
abc_tensors, grouped["m_pads"], grouped["m_actual"]
):
c_ref[:, :, 0].copy_(out[offset : offset + m, :])
offset += m_pad
local_results.append(c_ref)
return local_results
def _emit_from_3d(out, grouped_pad):
local_results = []
for idx, (_, _, c_ref) in enumerate(abc_tensors):
c_ref[:, :, 0].copy_(out[idx, : grouped_pad["m_actual"][idx], :])
local_results.append(c_ref)
return local_results
grouped_mm_v2 = _get_grouped_mm_v2()
block_scale, global_scale, block_swizzle, global_swizzle = _get_scale_swizzle()
k_val = problem_sizes[0][2] if problem_sizes else 0
strategy_key = tuple(problem_sizes)
strategy = _grouped_strategy_cache.get(strategy_key)
if (
grouped_mm_v2 is not None
and block_scale is not None
and block_swizzle is not None
and strategy != "skip_v2"
):
try:
grouped2d = None
grouped3d = None
if strategy is not None:
attempts = [strategy]
else:
if global_scale is not None:
attempts = [
"2d:stack:nk:group",
"3d:stack:nk:group",
"2d:stack:kn:group",
"3d:stack:kn:group",
"2d:concat:nk:group",
"2d:concat:kn:group",
"3d:stack:nk:scalar",
"3d:stack:kn:scalar",
]
else:
attempts = [
"2d:stack:nk:none",
"3d:stack:nk:none",
"2d:stack:kn:none",
"3d:stack:kn:none",
"2d:concat:nk:none",
"2d:concat:kn:none",
]
for attempt in attempts:
try:
mode, scale_layout, b_layout, global_layout = attempt.split(":")
except ValueError:
mode, scale_layout, b_layout, global_layout = "2d", "stack", "nk", "group"
if mode == "3d":
if grouped3d is None:
grouped3d = _build_grouped_inputs_padded(
abc_tensors, sfasfb_reordered_tensors, problem_sizes
)
grouped = grouped3d
a = grouped["a"]
b = grouped["b_nk"] if b_layout == "nk" else grouped["b_kn"]
scale_a_block = grouped["scale_a"]
scale_b_block = grouped["scale_b"]
offs = None
offs_cpu = None
emit = _emit_from_3d
else:
if grouped2d is None:
grouped2d = _build_grouped_inputs(
abc_tensors, sfasfb_reordered_tensors, problem_sizes
)
grouped = grouped2d
a = grouped["a"]
scale_a_concat = grouped["scale_a"]
scale_a_stack = grouped["scale_a_stack"]
if scale_layout == "stack" and scale_a_stack is not None:
scale_a_block = scale_a_stack
else:
scale_a_block = scale_a_concat
scale_b_block = grouped["scale_b"]
b = grouped["b_nk"] if b_layout == "nk" else grouped["b_kn"]
offs = grouped["offs"]
offs_cpu = grouped["offs_cpu"]
emit = _emit_from_2d
if scale_a_block is None or scale_b_block is None:
continue
if global_scale is not None and global_layout != "none":
per_group = global_layout == "group"
global_a = _get_global_scale(len(abc_tensors), a.device, per_group)
global_b = _get_global_scale(len(abc_tensors), a.device, per_group)
scale_a = [scale_a_block, global_a]
scale_b = [scale_b_block, global_b]
scale_recipe_a = [block_scale, global_scale]
scale_recipe_b = [block_scale, global_scale]
swizzle_a = [
block_swizzle,
global_swizzle if global_swizzle is not None else block_swizzle,
]
swizzle_b = [
block_swizzle,
global_swizzle if global_swizzle is not None else block_swizzle,
]
else:
scale_a = scale_a_block
scale_b = scale_b_block
scale_recipe_a = block_scale
scale_recipe_b = block_scale
swizzle_a = block_swizzle
swizzle_b = block_swizzle
out = _try_scaled_grouped_mm_v2(
grouped_mm_v2,
a,
b,
scale_a,
scale_recipe_a,
scale_b,
scale_recipe_b,
swizzle_a,
swizzle_b,
offs,
offs_cpu,
torch.float16,
)
if out is None:
out = _try_scaled_grouped_mm_v2(
grouped_mm_v2,
a,
b,
scale_a,
scale_recipe_a,
scale_b,
scale_recipe_b,
swizzle_a,
swizzle_b,
offs,
offs_cpu,
torch.bfloat16,
)
if out is not None:
out = out.to(torch.float16)
if out is not None:
_grouped_strategy_cache[strategy_key] = attempt
result_tensors = emit(out, grouped)
return result_tensors
_grouped_strategy_cache[strategy_key] = "skip_v2"
except Exception:
_grouped_strategy_cache[strategy_key] = "skip_v2"
grouped_mm = _get_grouped_mm()
strategy_v1 = _grouped_strategy_cache_v1.get(strategy_key)
if grouped_mm is not None and strategy_v1 != "skip_v1":
try:
grouped = _build_grouped_inputs(
abc_tensors, sfasfb_reordered_tensors, problem_sizes
)
a = grouped["a"]
scale_a_block = grouped["scale_a"]
scale_b_block = grouped["scale_b"]
b_nk = grouped["b_nk"]
b_kn = grouped["b_kn"]
attempts = [strategy_v1] if strategy_v1 is not None else ["kn", "nk"]
for attempt in attempts:
b = b_nk if attempt == "nk" else b_kn
out = _try_scaled_grouped_mm_v1(
grouped_mm,
a,
b,
scale_a_block,
scale_b_block,
grouped["offs"],
grouped["offs_cpu"],
torch.float16,
)
if out is None:
out = _try_scaled_grouped_mm_v1(
grouped_mm,
a,
b,
scale_a_block,
scale_b_block,
grouped["offs"],
grouped["offs_cpu"],
torch.bfloat16,
)
if out is not None:
out = out.to(torch.float16)
if out is not None:
_grouped_strategy_cache_v1[strategy_key] = attempt
result_tensors = _emit_from_2d(out, grouped)
return result_tensors
_grouped_strategy_cache_v1[strategy_key] = "skip_v1"
except Exception:
_grouped_strategy_cache_v1[strategy_key] = "skip_v1"
for (a_ref, b_ref, c_ref), (sfa_reordered, sfb_reordered), (_, _, _, l) in zip(
abc_tensors, sfasfb_reordered_tensors, problem_sizes
):
for l_idx in range(l):
scale_a = blocked_from_reordered(sfa_reordered, l_idx)
scale_b = blocked_from_reordered(sfb_reordered, l_idx)
mat_a = a_ref[:, :, l_idx].view(torch.float4_e2m1fn_x2)
mat_b = b_ref[:, :, l_idx].transpose(0, 1).view(torch.float4_e2m1fn_x2)
_scaled_mm_out(
mat_a,
mat_b,
scale_a,
scale_b,
c_ref[:, :, l_idx],
)
result_tensors.append(c_ref)
return result_tensors
scrolls · 945 lines total
Source code from GPU Mode and the KernelBot dataset · June 9 Researcher Reciprocity License v1.0
Changes from previous submission
Against this author's previous submission submission 411292.
⋯ 9 unchanged linespass_CPP_B64 = "CiAgICAjaW5jbHVkZSA8dG9yY2gvZXh0ZW5zaW9uLmg+CiAgICAjaW5jbHVkZSA8dmVjdG9yPgoKICAgIHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+IGdyb3VwZWRfZ2VtbV8xc20oCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIEEsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIEIsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIEMsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIFNGQSwKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgU0ZCKTsKCiAgICBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiBncm91cGVkX2dlbW1fMnNtKAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBBLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBCLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBDLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBTRkEsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIFNGQik7CiAgICA="- _CU_B64 = "CiAgICAjaW5jbHVkZSA8dG9yY2gvZXh0ZW5zaW9uLmg+CiAgICAjaW5jbHVkZSA8QVRlbi9jdWRhL0NVREFDb250ZXh0Lmg+CiAgICAjaW5jbHVkZSA8YzEwL2N1ZGEvQ1VEQVN0cmVhbS5oPgogICAgI2luY2x1ZGUgPGMxMC9jdWRhL0NVREFHdWFyZC5oPgogICAgI2luY2x1ZGUgPHZlY3Rvcj4KICAgICNpbmNsdWRlIDxzdGRleGNlcHQ+CiAgICAjaW5jbHVkZSA8dHlwZV90cmFpdHM+CgogICAgI2lmZGVmIF9fQ1VEQV9OT19IQUxGX09QRVJBVE9SU19fCiAgICAjdW5kZWYgX19DVURBX05PX0hBTEZfT1BFUkFUT1JTX18KICAgICNlbmRpZgogICAgI2lmZGVmIF9fQ1VEQV9OT19IQUxGX0NPTlZFUlNJT05TX18KICAgICN1bmRlZiBfX0NVREFfTk9fSEFMRl9DT05WRVJTSU9OU19fCiAgICAjZW5kaWYKICAgICNpZmRlZiBfX0NVREFfTk9fSEFMRjJfT1BFUkFUT1JTX18KICAgICN1bmRlZiBfX0NVREFfTk9fSEFMRjJfT1BFUkFUT1JTX18KICAgICNlbmRpZgoKICAgICNpbmNsdWRlIDxjdWRhX3J1bnRpbWUuaD4KICAgICNpZiBkZWZpbmVkKF9fQ1VEQV9BUkNIX18pICYmICFkZWZpbmVkKENVVExBU1NfQVJDSF9NTUFfU00xMDBBX0VOQUJMRUQpCiAgICAjZGVmaW5lIENVVExBU1NfQVJDSF9NTUFfU00xMDBBX0VOQUJMRUQgMQogICAgI2VuZGlmCiAgICAjaW5jbHVkZSAiY3V0bGFzcy9jdXRsYXNzLmgiCiAgICAjaW5jbHVkZSAiY3V0ZS90ZW5zb3IuaHBwIgogICAgI2luY2x1ZGUgImN1dGxhc3MvdGVuc29yX3JlZi5oIgogICAgI2luY2x1ZGUgImN1dGxhc3MvZXBpbG9ndWUvY29sbGVjdGl2ZS9kZWZhdWx0X2VwaWxvZ3VlLmhwcCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2VwaWxvZ3VlL3RocmVhZC9saW5lYXJfY29tYmluYXRpb24uaCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2dlbW0vZGlzcGF0Y2hfcG9saWN5LmhwcCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2dlbW0vZ3JvdXBfYXJyYXlfcHJvYmxlbV9zaGFwZS5ocHAiCiAgICAjaW5jbHVkZSAiY3V0bGFzcy9nZW1tL2NvbGxlY3RpdmUvY29sbGVjdGl2ZV9idWlsZGVyLmhwcCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2VwaWxvZ3VlL2NvbGxlY3RpdmUvY29sbGVjdGl2ZV9idWlsZGVyLmhwcCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2dlbW0vZGV2aWNlL2dlbW1fdW5pdmVyc2FsX2FkYXB0ZXIuaCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2dlbW0va2VybmVsL2dlbW1fdW5pdmVyc2FsLmhwcCIKICAgICNpbmNsdWRlICJjdXRsYXNzL3V0aWwvcGFja2VkX3N0cmlkZS5ocHAiCiAgICAjaW5jbHVkZSAiY3V0bGFzcy9rZXJuZWxfaGFyZHdhcmVfaW5mby5oIgogICAgI2luY2x1ZGUgImN1dGxhc3MvdXRpbC9kZXZpY2VfbWVtb3J5LmgiCiAgICAjaW5jbHVkZSAiY3V0bGFzcy9nZW1tL2tlcm5lbC90aWxlX3NjaGVkdWxlcl9wYXJhbXMuaCIKCiAgICAjZGVmaW5lIENVVExBU1NfQ0hFQ0soc3RhdHVzKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXAogICAgICBkbyB7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwKICAgICAgICBjdXRsYXNzOjpTdGF0dXMgX3N0YXR1cyA9IChzdGF0dXMpOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcCiAgICAgICAgaWYgKF9zdGF0dXMgIT0gY3V0bGFzczo6U3RhdHVzOjprU3VjY2VzcykgeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXAogICAgICAgICAgdGhyb3cgc3RkOjpydW50aW1lX2Vycm9yKCJDVVRMQVNTIGVycm9yIik7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwKICAgICAgICB9ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcCiAgICAgIH0gd2hpbGUgKDApCgogICAgI2RlZmluZSBDVURBX0NIRUNLKGV4cHIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXAogICAgICBkbyB7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwKICAgICAgICBjdWRhRXJyb3JfdCBfZXJyID0gKGV4cHIpOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcCiAgICAgICAgaWYgKF9lcnIgIT0gY3VkYVN1Y2Nlc3MpIHsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXAogICAgICAgICAgdGhyb3cgc3RkOjpydW50aW1lX2Vycm9yKGN1ZGFHZXRFcnJvclN0cmluZyhfZXJyKSk7ICAgICAgICAgICAgICAgICAgICAgICAgIFwKICAgICAgICB9ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcCiAgICAgIH0gd2hpbGUgKDApCgogICAgdXNpbmcgUHJvYmxlbVNoYXBlID0gY3V0bGFzczo6Z2VtbTo6R3JvdXBQcm9ibGVtU2hhcGU8Y3V0ZTo6U2hhcGU8aW50LGludCxpbnQ+PjsKICAgIHVzaW5nIEVsZW1lbnRJbnB1dCA9IGN1dGxhc3M6OmZsb2F0X2UybTFfdDsKICAgIHVzaW5nIEVsZW1lbnRTRiAgICA9IGN1dGxhc3M6OmZsb2F0X3VlNG0zX3Q7CiAgICB1c2luZyBFbGVtZW50QyAgICAgPSBjdXRsYXNzOjpoYWxmX3Q7CgogICAgdXNpbmcgRWxlbWVudEEgPSBjdXRsYXNzOjpudl9mbG9hdDRfdDxFbGVtZW50SW5wdXQ+OwogICAgdXNpbmcgTGF5b3V0QSAgPSBjdXRsYXNzOjpsYXlvdXQ6OlJvd01ham9yOwogICAgY29uc3RleHByIGludCBBbGlnbm1lbnRBICA9IDMyOwoKICAgIHVzaW5nIEVsZW1lbnRCID0gY3V0bGFzczo6bnZfZmxvYXQ0X3Q8RWxlbWVudElucHV0PjsKICAgIHVzaW5nIExheW91dEIgID0gY3V0bGFzczo6bGF5b3V0OjpDb2x1bW5NYWpvcjsKICAgIGNvbnN0ZXhwciBpbnQgQWxpZ25tZW50QiAgPSAzMjsKCiAgICB1c2luZyBFbGVtZW50RCA9IEVsZW1lbnRDOwogICAgdXNpbmcgTGF5b3V0QyAgPSBjdXRsYXNzOjpsYXlvdXQ6OlJvd01ham9yOwogICAgY29uc3RleHByIGludCBBbGlnbm1lbnRDICA9IDEyOCAvIGN1dGxhc3M6OnNpemVvZl9iaXRzPEVsZW1lbnRDPjo6dmFsdWU7CiAgICBjb25zdGV4cHIgaW50IEFsaWdubWVudEQgID0gMTI4IC8gY3V0bGFzczo6c2l6ZW9mX2JpdHM8RWxlbWVudEQ+Ojp2YWx1ZTsKICAgIHVzaW5nIEVsZW1lbnRBY2N1bXVsYXRvciAgPSBmbG9hdDsKCiAgICB1c2luZyBBcmNoVGFnID0gY3V0bGFzczo6YXJjaDo6U20xMDA7CiAgICB1c2luZyBPcGVyYXRvckNsYXNzID0gY3V0bGFzczo6YXJjaDo6T3BDbGFzc0Jsb2NrU2NhbGVkVGVuc29yT3A7CiAgICB1c2luZyBTdGFnZUNvdW50VHlwZSA9IGN1dGxhc3M6OmdlbW06OmNvbGxlY3RpdmU6OlN0YWdlQ291bnRBdXRvOwogICAgdXNpbmcgQ2x1c3RlclNoYXBlID0gY3V0ZTo6U2hhcGU8aW50MzJfdCxpbnQzMl90LGN1dGU6Ol8xPjsKCiAgICBzdHJ1Y3QgTU1BMVNNQ29uZmlnIHsKICAgICAgdXNpbmcgTW1hVGlsZVNoYXBlICAgICA9IGN1dGU6OlNoYXBlPGN1dGU6Ol8xMjgsY3V0ZTo6XzEyOCxjdXRlOjpfMjU2PjsKICAgICAgdXNpbmcgS2VybmVsU2NoZWR1bGUgICA9IGN1dGxhc3M6OmdlbW06Oktlcm5lbFB0ckFycmF5VG1hV2FycFNwZWNpYWxpemVkMVNtTnZmNFNtMTAwOwogICAgICB1c2luZyBFcGlsb2d1ZVNjaGVkdWxlID0gY3V0bGFzczo6ZXBpbG9ndWU6OlB0ckFycmF5VG1hV2FycFNwZWNpYWxpemVkMVNtOwogICAgfTsKCiAgICBzdHJ1Y3QgTU1BMlNNQ29uZmlnIHsKICAgICAgdXNpbmcgTW1hVGlsZVNoYXBlICAgICA9IGN1dGU6OlNoYXBlPGN1dGU6Ol8yNTYsY3V0ZTo6XzEyOCxjdXRlOjpfMjU2PjsKICAgICAgdXNpbmcgS2VybmVsU2NoZWR1bGUgICA9IGN1dGxhc3M6OmdlbW06Oktlcm5lbFB0ckFycmF5VG1hV2FycFNwZWNpYWxpemVkMlNtTnZmNFNtMTAwOwogICAgICB1c2luZyBFcGlsb2d1ZVNjaGVkdWxlID0gY3V0bGFzczo6ZXBpbG9ndWU6OlB0ckFycmF5VG1hV2FycFNwZWNpYWxpemVkMlNtOwogICAgfTsKCiAgICB1c2luZyBDb2xsZWN0aXZlRXBpbG9ndWUxU00gPSB0eXBlbmFtZSBjdXRsYXNzOjplcGlsb2d1ZTo6Y29sbGVjdGl2ZTo6Q29sbGVjdGl2ZUJ1aWxkZXI8CiAgICAgICAgQXJjaFRhZywgT3BlcmF0b3JDbGFzcywKICAgICAgICB0eXBlbmFtZSBNTUExU01Db25maWc6Ok1tYVRpbGVTaGFwZSwgQ2x1c3RlclNoYXBlLAogICAgICAgIGN1dGU6OlNoYXBlPGN1dGU6Ol8xMjgsY3V0ZTo6XzY0PiwKICAgICAgICBFbGVtZW50QWNjdW11bGF0b3IsIEVsZW1lbnRBY2N1bXVsYXRvciwKICAgICAgICBFbGVtZW50QywgTGF5b3V0QyAqLCBBbGlnbm1lbnRDLAogICAgICAgIEVsZW1lbnRELCBMYXlvdXRDICosIEFsaWdubWVudEQsCiAgICAgICAgdHlwZW5hbWUgTU1BMVNNQ29uZmlnOjpFcGlsb2d1ZVNjaGVkdWxlCiAgICA+OjpDb2xsZWN0aXZlT3A7CgogICAgdXNpbmcgQ29sbGVjdGl2ZU1haW5sb29wMVNNID0gdHlwZW5hbWUgY3V0bGFzczo6Z2VtbTo6Y29sbGVjdGl2ZTo6Q29sbGVjdGl2ZUJ1aWxkZXI8CiAgICAgIEFyY2hUYWcsIE9wZXJhdG9yQ2xhc3MsCiAgICAgIEVsZW1lbnRBLCBMYXlvdXRBICosIEFsaWdubWVudEEsCiAgICAgIEVsZW1lbnRCLCBMYXlvdXRCICosIEFsaWdubWVudEIsCiAgICAgIEVsZW1lbnRBY2N1bXVsYXRvciwKICAgICAgdHlwZW5hbWUgTU1BMVNNQ29uZmlnOjpNbWFUaWxlU2hhcGUsIENsdXN0ZXJTaGFwZSwKICAgICAgY3V0bGFzczo6Z2VtbTo6Y29sbGVjdGl2ZTo6U3RhZ2VDb3VudEF1dG9DYXJ2ZW91dDwKICAgICAgICBzdGF0aWNfY2FzdDxpbnQ+KHNpemVvZih0eXBlbmFtZSBDb2xsZWN0aXZlRXBpbG9ndWUxU006OlNoYXJlZFN0b3JhZ2UpKT4sCiAgICAgIHR5cGVuYW1lIE1NQTFTTUNvbmZpZzo6S2VybmVsU2NoZWR1bGUKICAgID46OkNvbGxlY3RpdmVPcDsKCiAgICB1c2luZyBHZW1tS2VybmVsMVNNID0gY3V0bGFzczo6Z2VtbTo6a2VybmVsOjpHZW1tVW5pdmVyc2FsPAogICAgICAgIFByb2JsZW1TaGFwZSwKICAgICAgICBDb2xsZWN0aXZlTWFpbmxvb3AxU00sCiAgICAgICAgQ29sbGVjdGl2ZUVwaWxvZ3VlMVNNCiAgICA+OwogICAgdXNpbmcgR2VtbTFTTSA9IGN1dGxhc3M6OmdlbW06OmRldmljZTo6R2VtbVVuaXZlcnNhbEFkYXB0ZXI8R2VtbUtlcm5lbDFTTT47CgogICAgdXNpbmcgQ29sbGVjdGl2ZUVwaWxvZ3VlMlNNID0gdHlwZW5hbWUgY3V0bGFzczo6ZXBpbG9ndWU6OmNvbGxlY3RpdmU6OkNvbGxlY3RpdmVCdWlsZGVyPAogICAgICAgIEFyY2hUYWcsIE9wZXJhdG9yQ2xhc3MsCiAgICAgICAgdHlwZW5hbWUgTU1BMlNNQ29uZmlnOjpNbWFUaWxlU2hhcGUsIENsdXN0ZXJTaGFwZSwKICAgICAgICBjdXRlOjpTaGFwZTxjdXRlOjpfMTI4LGN1dGU6Ol82ND4sCiAgICAgICAgRWxlbWVudEFjY3VtdWxhdG9yLCBFbGVtZW50QWNjdW11bGF0b3IsCiAgICAgICAgRWxlbWVudEMsIExheW91dEMgKiwgQWxpZ25tZW50QywKICAgICAgICBFbGVtZW50RCwgTGF5b3V0QyAqLCBBbGlnbm1lbnRELAogICAgICAgIHR5cGVuYW1lIE1NQTJTTUNvbmZpZzo6RXBpbG9ndWVTY2hlZHVsZQogICAgPjo6Q29sbGVjdGl2ZU9wOwoKICAgIHVzaW5nIENvbGxlY3RpdmVNYWlubG9vcDJTTSA9IHR5cGVuYW1lIGN1dGxhc3M6OmdlbW06OmNvbGxlY3RpdmU6OkNvbGxlY3RpdmVCdWlsZGVyPAogICAgICBBcmNoVGFnLCBPcGVyYXRvckNsYXNzLAogICAgICBFbGVtZW50QSwgTGF5b3V0QSAqLCBBbGlnbm1lbnRBLAogICAgICBFbGVtZW50QiwgTGF5b3V0QiAqLCBBbGlnbm1lbnRCLAogICAgICBFbGVtZW50QWNjdW11bGF0b3IsCiAgICAgIHR5cGVuYW1lIE1NQTJTTUNvbmZpZzo6TW1hVGlsZVNoYXBlLCBDbHVzdGVyU2hhcGUsCiAgICAgIGN1dGxhc3M6OmdlbW06OmNvbGxlY3RpdmU6OlN0YWdlQ291bnRBdXRvQ2FydmVvdXQ8CiAgICAgICAgc3RhdGljX2Nhc3Q8aW50PihzaXplb2YodHlwZW5hbWUgQ29sbGVjdGl2ZUVwaWxvZ3VlMlNNOjpTaGFyZWRTdG9yYWdlKSk+LAogICAgICB0eXBlbmFtZSBNTUEyU01Db25maWc6Oktlcm5lbFNjaGVkdWxlCiAgICA+OjpDb2xsZWN0aXZlT3A7CgogICAgdXNpbmcgR2VtbUtlcm5lbDJTTSA9IGN1dGxhc3M6OmdlbW06Omtlcm5lbDo6R2VtbVVuaXZlcnNhbDwKICAgICAgICBQcm9ibGVtU2hhcGUsCiAgICAgICAgQ29sbGVjdGl2ZU1haW5sb29wMlNNLAogICAgICAgIENvbGxlY3RpdmVFcGlsb2d1ZTJTTQogICAgPjsKICAgIHVzaW5nIEdlbW0yU00gPSBjdXRsYXNzOjpnZW1tOjpkZXZpY2U6OkdlbW1Vbml2ZXJzYWxBZGFwdGVyPEdlbW1LZXJuZWwyU00+OwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUPgogICAgc3RydWN0IFBpbm5lZEhvc3RCdWZmZXIgewogICAgICBUKiBwdHIgPSBudWxscHRyOwogICAgICBzaXplX3QgY291bnQgPSAwOwoKICAgICAgUGlubmVkSG9zdEJ1ZmZlcigpID0gZGVmYXVsdDsKICAgICAgZXhwbGljaXQgUGlubmVkSG9zdEJ1ZmZlcihzaXplX3QgbikgeyBhbGxvY2F0ZShuKTsgfQoKICAgICAgdm9pZCBhbGxvY2F0ZShzaXplX3QgbikgewogICAgICAgIGlmIChwdHIgJiYgY291bnQgPj0gbikgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICByZWxlYXNlKCk7CiAgICAgICAgY291bnQgPSBuOwogICAgICAgIENVREFfQ0hFQ0soY3VkYUhvc3RBbGxvYyhyZWludGVycHJldF9jYXN0PHZvaWQqKj4oJnB0ciksIG4gKiBzaXplb2YoVCksIGN1ZGFIb3N0QWxsb2NQb3J0YWJsZSkpOwogICAgICB9CgogICAgICB2b2lkIHJlbGVhc2UoKSB7CiAgICAgICAgaWYgKHB0cikgewogICAgICAgICAgY3VkYUZyZWVIb3N0KHB0cik7CiAgICAgICAgICBwdHIgPSBudWxscHRyOwogICAgICAgICAgY291bnQgPSAwOwogICAgICAgIH0KICAgICAgfQoKICAgICAgflBpbm5lZEhvc3RCdWZmZXIoKSB7IHJlbGVhc2UoKTsgfQoKICAgICAgVCogZGF0YSgpIGNvbnN0IHsgcmV0dXJuIHB0cjsgfQogICAgICBUJiBvcGVyYXRvcltdKHNpemVfdCBpZHgpIHsgcmV0dXJuIHB0cltpZHhdOyB9CiAgICB9OwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUPgogICAgc3RydWN0IERldmljZUJ1ZmZlciB7CiAgICAgIFQqIHB0ciA9IG51bGxwdHI7CiAgICAgIHNpemVfdCBjb3VudCA9IDA7CgogICAgICBEZXZpY2VCdWZmZXIoKSA9IGRlZmF1bHQ7CiAgICAgIGV4cGxpY2l0IERldmljZUJ1ZmZlcihzaXplX3QgbikgeyBhbGxvY2F0ZShuKTsgfQoKICAgICAgdm9pZCBhbGxvY2F0ZShzaXplX3QgbikgewogICAgICAgIGlmIChwdHIgJiYgY291bnQgPj0gbikgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICByZWxlYXNlKCk7CiAgICAgICAgY291bnQgPSBuOwogICAgICAgIENVREFfQ0hFQ0soY3VkYU1hbGxvYyhyZWludGVycHJldF9jYXN0PHZvaWQqKj4oJnB0ciksIG4gKiBzaXplb2YoVCkpKTsKICAgICAgfQoKICAgICAgdm9pZCByZWxlYXNlKCkgewogICAgICAgIGlmIChwdHIpIHsKICAgICAgICAgIGN1ZGFGcmVlKHB0cik7CiAgICAgICAgICBwdHIgPSBudWxscHRyOwogICAgICAgICAgY291bnQgPSAwOwogICAgICAgIH0KICAgICAgfQoKICAgICAgfkRldmljZUJ1ZmZlcigpIHsgcmVsZWFzZSgpOyB9CgogICAgICBUKiBnZXQoKSBjb25zdCB7IHJldHVybiBwdHI7IH0KCiAgICAgIHZvaWQgY29weV9mcm9tX2hvc3QoY29uc3QgVCogaG9zdCwgc2l6ZV90IG4sIGN1ZGFTdHJlYW1fdCBzdHJlYW0pIHsKICAgICAgICBDVURBX0NIRUNLKGN1ZGFNZW1jcHlBc3luYyhwdHIsIGhvc3QsIG4gKiBzaXplb2YoVCksIGN1ZGFNZW1jcHlIb3N0VG9EZXZpY2UsIHN0cmVhbSkpOwogICAgICB9CiAgICB9OwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBHZW1tPgogICAgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4gcnVuX2dyb3VwZWRfaW1wbCgKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgQSwKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgQiwKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgQywKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgU0ZBLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBTRkIpIHsKCiAgICAgIFRPUkNIX0NIRUNLKEEuc2l6ZSgpID09IEIuc2l6ZSgpLCAiQS9CIHNpemUgbWlzbWF0Y2giKTsKICAgICAgVE9SQ0hfQ0hFQ0soQS5zaXplKCkgPT0gQy5zaXplKCksICJBL0Mgc2l6ZSBtaXNtYXRjaCIpOwogICAgICBUT1JDSF9DSEVDSyhBLnNpemUoKSA9PSBTRkEuc2l6ZSgpLCAiQS9TRkEgc2l6ZSBtaXNtYXRjaCIpOwogICAgICBUT1JDSF9DSEVDSyhBLnNpemUoKSA9PSBTRkIuc2l6ZSgpLCAiQS9TRkIgc2l6ZSBtaXNtYXRjaCIpOwogICAgICBjb25zdCBpbnQzMl90IGdyb3VwcyA9IHN0YXRpY19jYXN0PGludDMyX3Q+KEEuc2l6ZSgpKTsKICAgICAgVE9SQ0hfQ0hFQ0soZ3JvdXBzID4gMCwgIk5vIGdyb3VwcyIpOwoKICAgICAgaW50IGRldmljZV9pZCA9IEFbMF0uZ2V0X2RldmljZSgpOwogICAgICBjMTA6OmN1ZGE6OkNVREFHdWFyZCBkZXZpY2VfZ3VhcmQoZGV2aWNlX2lkKTsKCiAgICAgIHVzaW5nIFN0cmlkZUEgPSB0eXBlbmFtZSBHZW1tOjpHZW1tS2VybmVsOjpJbnRlcm5hbFN0cmlkZUE7CiAgICAgIHVzaW5nIFN0cmlkZUIgPSB0eXBlbmFtZSBHZW1tOjpHZW1tS2VybmVsOjpJbnRlcm5hbFN0cmlkZUI7CiAgICAgIHVzaW5nIFN0cmlkZUMgPSB0eXBlbmFtZSBHZW1tOjpHZW1tS2VybmVsOjpJbnRlcm5hbFN0cmlkZUM7CiAgICAgIHVzaW5nIFN0cmlkZUQgPSB0eXBlbmFtZSBHZW1tOjpHZW1tS2VybmVsOjpJbnRlcm5hbFN0cmlkZUQ7CiAgICAgIHVzaW5nIExheW91dFNGQSA9IHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkNvbGxlY3RpdmVNYWlubG9vcDo6SW50ZXJuYWxMYXlvdXRTRkE7CiAgICAgIHVzaW5nIExheW91dFNGQiA9IHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkNvbGxlY3RpdmVNYWlubG9vcDo6SW50ZXJuYWxMYXlvdXRTRkI7CiAgICAgIHVzaW5nIFNtMXh4QmxrU2NhbGVkQ29uZmlnID0gdHlwZW5hbWUgR2VtbTo6R2VtbUtlcm5lbDo6Q29sbGVjdGl2ZU1haW5sb29wOjpTbTF4eEJsa1NjYWxlZENvbmZpZzsKCiAgICAgIHN0YXRpYyBzaXplX3QgY2FwYWNpdHkgPSAwOwogICAgICBzdGF0aWMgaW50IGNhY2hlZF9kZXZpY2UgPSAtMTsKICAgICAgc3RhdGljIFBpbm5lZEhvc3RCdWZmZXI8dHlwZW5hbWUgR2VtbTo6RWxlbWVudEEgY29uc3QqPiBwdHJfQV9ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjx0eXBlbmFtZSBHZW1tOjpFbGVtZW50QiBjb25zdCo+IHB0cl9CX2hvc3Q7CiAgICAgIHN0YXRpYyBQaW5uZWRIb3N0QnVmZmVyPHR5cGVuYW1lIEdlbW06OkVsZW1lbnRDIGNvbnN0Kj4gcHRyX0NfaG9zdDsKICAgICAgc3RhdGljIFBpbm5lZEhvc3RCdWZmZXI8dHlwZW5hbWUgR2VtbTo6RXBpbG9ndWVPdXRwdXRPcDo6RWxlbWVudE91dHB1dCo+IHB0cl9EX2hvc3Q7CiAgICAgIHN0YXRpYyBQaW5uZWRIb3N0QnVmZmVyPHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkVsZW1lbnRTRiBjb25zdCo+IHB0cl9TRkFfaG9zdDsKICAgICAgc3RhdGljIFBpbm5lZEhvc3RCdWZmZXI8dHlwZW5hbWUgR2VtbTo6R2VtbUtlcm5lbDo6RWxlbWVudFNGIGNvbnN0Kj4gcHRyX1NGQl9ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjxTdHJpZGVBPiBzdHJpZGVfQV9ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjxTdHJpZGVCPiBzdHJpZGVfQl9ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjxTdHJpZGVDPiBzdHJpZGVfQ19ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjxTdHJpZGVEPiBzdHJpZGVfRF9ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjxMYXlvdXRTRkE+IGxheW91dF9TRkFfaG9zdDsKICAgICAgc3RhdGljIFBpbm5lZEhvc3RCdWZmZXI8TGF5b3V0U0ZCPiBsYXlvdXRfU0ZCX2hvc3Q7CiAgICAgIHN0YXRpYyBQaW5uZWRIb3N0QnVmZmVyPHR5cGVuYW1lIFByb2JsZW1TaGFwZTo6VW5kZXJseWluZ1Byb2JsZW1TaGFwZT4gcHJvYmxlbV9zaXplc19ob3N0OwoKICAgICAgc3RhdGljIERldmljZUJ1ZmZlcjx0eXBlbmFtZSBQcm9ibGVtU2hhcGU6OlVuZGVybHlpbmdQcm9ibGVtU2hhcGU+IHByb2JsZW1fc2l6ZXNfZGV2aWNlOwogICAgICBzdGF0aWMgRGV2aWNlQnVmZmVyPHR5cGVuYW1lIEdlbW06OkVsZW1lbnRBIGNvbnN0Kj4gcHRyX0E7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8dHlwZW5hbWUgR2VtbTo6RWxlbWVudEIgY29uc3QqPiBwdHJfQjsKICAgICAgc3RhdGljIERldmljZUJ1ZmZlcjx0eXBlbmFtZSBHZW1tOjpHZW1tS2VybmVsOjpFbGVtZW50U0YgY29uc3QqPiBwdHJfU0ZBOwogICAgICBzdGF0aWMgRGV2aWNlQnVmZmVyPHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkVsZW1lbnRTRiBjb25zdCo+IHB0cl9TRkI7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8dHlwZW5hbWUgR2VtbTo6RWxlbWVudEMgY29uc3QqPiBwdHJfQzsKICAgICAgc3RhdGljIERldmljZUJ1ZmZlcjx0eXBlbmFtZSBHZW1tOjpFcGlsb2d1ZU91dHB1dE9wOjpFbGVtZW50T3V0cHV0Kj4gcHRyX0Q7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8U3RyaWRlQT4gc3RyaWRlX0E7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8U3RyaWRlQj4gc3RyaWRlX0I7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8U3RyaWRlQz4gc3RyaWRlX0M7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8U3RyaWRlRD4gc3RyaWRlX0Q7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8TGF5b3V0U0ZBPiBsYXlvdXRfU0ZBOwogICAgICBzdGF0aWMgRGV2aWNlQnVmZmVyPExheW91dFNGQj4gbGF5b3V0X1NGQjsKICAgICAgc3RhdGljIHNpemVfdCB3b3Jrc3BhY2Vfc2l6ZV9jYWNoZWQgPSAwOwogICAgICBzdGF0aWMgdG9yY2g6OlRlbnNvciB3b3Jrc3BhY2VfdGVuc29yOwoKICAgICAgaWYgKGNhY2hlZF9kZXZpY2UgIT0gZGV2aWNlX2lkIHx8IGNhcGFjaXR5IDwgc3RhdGljX2Nhc3Q8c2l6ZV90Pihncm91cHMpKSB7CiAgICAgICAgY2FjaGVkX2RldmljZSA9IGRldmljZV9pZDsKICAgICAgICBjYXBhY2l0eSA9IHN0YXRpY19jYXN0PHNpemVfdD4oZ3JvdXBzKTsKICAgICAgICBwdHJfQV9ob3N0LmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX0JfaG9zdC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHB0cl9DX2hvc3QuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBwdHJfRF9ob3N0LmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX1NGQV9ob3N0LmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX1NGQl9ob3N0LmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgc3RyaWRlX0FfaG9zdC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHN0cmlkZV9CX2hvc3QuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBzdHJpZGVfQ19ob3N0LmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgc3RyaWRlX0RfaG9zdC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIGxheW91dF9TRkFfaG9zdC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIGxheW91dF9TRkJfaG9zdC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHByb2JsZW1fc2l6ZXNfaG9zdC5hbGxvY2F0ZShncm91cHMpOwoKICAgICAgICBwcm9ibGVtX3NpemVzX2RldmljZS5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHB0cl9BLmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX0IuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBwdHJfU0ZBLmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX1NGQi5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHB0cl9DLmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX0QuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBzdHJpZGVfQS5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHN0cmlkZV9CLmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgc3RyaWRlX0MuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBzdHJpZGVfRC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIGxheW91dF9TRkEuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBsYXlvdXRfU0ZCLmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgIH0KCiAgICAgIGZvciAoaW50MzJfdCBpID0gMDsgaSA8IGdyb3VwczsgKytpKSB7CiAgICAgICAgVE9SQ0hfQ0hFQ0soQVtpXS5pc19jdWRhKCksICJBIG11c3QgYmUgQ1VEQSIpOwogICAgICAgIFRPUkNIX0NIRUNLKEJbaV0uaXNfY3VkYSgpLCAiQiBtdXN0IGJlIENVREEiKTsKICAgICAgICBUT1JDSF9DSEVDSyhDW2ldLmlzX2N1ZGEoKSwgIkMgbXVzdCBiZSBDVURBIik7CiAgICAgICAgVE9SQ0hfQ0hFQ0soU0ZBW2ldLmlzX2N1ZGEoKSwgIlNGQSBtdXN0IGJlIENVREEiKTsKICAgICAgICBUT1JDSF9DSEVDSyhTRkJbaV0uaXNfY3VkYSgpLCAiU0ZCIG11c3QgYmUgQ1VEQSIpOwoKICAgICAgICBpbnQzMl90IG0gPSBzdGF0aWNfY2FzdDxpbnQzMl90PihBW2ldLnNpemUoMCkpOwogICAgICAgIGludDMyX3Qga19wYWNrZWQgPSBzdGF0aWNfY2FzdDxpbnQzMl90PihBW2ldLnNpemUoMSkpOwogICAgICAgIGludDMyX3QgayA9IGtfcGFja2VkICogMjsKICAgICAgICBpbnQzMl90IG4gPSBzdGF0aWNfY2FzdDxpbnQzMl90PihCW2ldLnNpemUoMCkpOwogICAgICAgIFRPUkNIX0NIRUNLKEJbaV0uc2l6ZSgxKSAqIDIgPT0gaywgIksgbWlzbWF0Y2giKTsKICAgICAgICBUT1JDSF9DSEVDSyhDW2ldLnNpemUoMCkgPT0gbSAmJiBDW2ldLnNpemUoMSkgPT0gbiwgIkMgc2hhcGUgbWlzbWF0Y2giKTsKCiAgICAgICAgcHJvYmxlbV9zaXplc19ob3N0W2ldID0gY3V0ZTo6bWFrZV9zaGFwZShtLCBuLCBrKTsKICAgICAgICBzdHJpZGVfQV9ob3N0W2ldID0gY3V0bGFzczo6bWFrZV9jdXRlX3BhY2tlZF9zdHJpZGUoU3RyaWRlQXt9LCB7bSwgaywgMX0pOwogICAgICAgIHN0cmlkZV9CX2hvc3RbaV0gPSBjdXRsYXNzOjptYWtlX2N1dGVfcGFja2VkX3N0cmlkZShTdHJpZGVCe30sIHtuLCBrLCAxfSk7CiAgICAgICAgc3RyaWRlX0NfaG9zdFtpXSA9IGN1dGxhc3M6Om1ha2VfY3V0ZV9wYWNrZWRfc3RyaWRlKFN0cmlkZUN7fSwge20sIG4sIDF9KTsKICAgICAgICBzdHJpZGVfRF9ob3N0W2ldID0gY3V0bGFzczo6bWFrZV9jdXRlX3BhY2tlZF9zdHJpZGUoU3RyaWRlRHt9LCB7bSwgbiwgMX0pOwogICAgICAgIGxheW91dF9TRkFfaG9zdFtpXSA9IFNtMXh4QmxrU2NhbGVkQ29uZmlnOjp0aWxlX2F0b21fdG9fc2hhcGVfU0ZBKGN1dGU6Om1ha2Vfc2hhcGUobSwgbiwgaywgMSkpOwogICAgICAgIGxheW91dF9TRkJfaG9zdFtpXSA9IFNtMXh4QmxrU2NhbGVkQ29uZmlnOjp0aWxlX2F0b21fdG9fc2hhcGVfU0ZCKGN1dGU6Om1ha2Vfc2hhcGUobSwgbiwgaywgMSkpOwoKICAgICAgICBwdHJfQV9ob3N0W2ldID0gcmVpbnRlcnByZXRfY2FzdDx0eXBlbmFtZSBHZW1tOjpFbGVtZW50QSBjb25zdCo+KEFbaV0uZGF0YV9wdHIoKSk7CiAgICAgICAgcHRyX0JfaG9zdFtpXSA9IHJlaW50ZXJwcmV0X2Nhc3Q8dHlwZW5hbWUgR2VtbTo6RWxlbWVudEIgY29uc3QqPihCW2ldLmRhdGFfcHRyKCkpOwogICAgICAgIHB0cl9DX2hvc3RbaV0gPSByZWludGVycHJldF9jYXN0PHR5cGVuYW1lIEdlbW06OkVsZW1lbnRDIGNvbnN0Kj4oQ1tpXS5kYXRhX3B0cigpKTsKICAgICAgICBwdHJfRF9ob3N0W2ldID0gcmVpbnRlcnByZXRfY2FzdDx0eXBlbmFtZSBHZW1tOjpFcGlsb2d1ZU91dHB1dE9wOjpFbGVtZW50T3V0cHV0Kj4oQ1tpXS5kYXRhX3B0cigpKTsKICAgICAgICBwdHJfU0ZBX2hvc3RbaV0gPSByZWludGVycHJldF9jYXN0PHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkVsZW1lbnRTRiBjb25zdCo+KFNGQVtpXS5kYXRhX3B0cigpKTsKICAgICAgICBwdHJfU0ZCX2hvc3RbaV0gPSByZWludGVycHJldF9jYXN0PHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkVsZW1lbnRTRiBjb25zdCo+KFNGQltpXS5kYXRhX3B0cigpKTsKICAgICAgfQoKICAgICAgYXV0byBzdHJlYW1fb2JqID0gYzEwOjpjdWRhOjpnZXRDdXJyZW50Q1VEQVN0cmVhbShkZXZpY2VfaWQpOwogICAgICBjMTA6OmN1ZGE6OkNVREFTdHJlYW1HdWFyZCBzdHJlYW1fZ3VhcmQoc3RyZWFtX29iaik7CiAgICAgIGN1ZGFTdHJlYW1fdCBzdHJlYW0gPSBzdHJlYW1fb2JqLnN0cmVhbSgpOwogICAgICBwcm9ibGVtX3NpemVzX2RldmljZS5jb3B5X2Zyb21faG9zdChwcm9ibGVtX3NpemVzX2hvc3QuZGF0YSgpLCBncm91cHMsIHN0cmVhbSk7CiAgICAgIHB0cl9BLmNvcHlfZnJvbV9ob3N0KHB0cl9BX2hvc3QuZGF0YSgpLCBncm91cHMsIHN0cmVhbSk7CiAgICAgIHB0cl9CLmNvcHlfZnJvbV9ob3N0KHB0cl9CX2hvc3QuZGF0YSgpLCBncm91cHMsIHN0cmVhbSk7CiAgICAgIHB0cl9TRkEuY29weV9mcm9tX2hvc3QocHRyX1NGQV9ob3N0LmRhdGEoKSwgZ3JvdXBzLCBzdHJlYW0pOwogICAgICBwdHJfU0ZCLmNvcHlfZnJvbV9ob3N0KHB0cl9TRkJfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgcHRyX0MuY29weV9mcm9tX2hvc3QocHRyX0NfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgcHRyX0QuY29weV9mcm9tX2hvc3QocHRyX0RfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgc3RyaWRlX0EuY29weV9mcm9tX2hvc3Qoc3RyaWRlX0FfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgc3RyaWRlX0IuY29weV9mcm9tX2hvc3Qoc3RyaWRlX0JfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgc3RyaWRlX0MuY29weV9mcm9tX2hvc3Qoc3RyaWRlX0NfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgc3RyaWRlX0QuY29weV9mcm9tX2hvc3Qoc3RyaWRlX0RfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgbGF5b3V0X1NGQS5jb3B5X2Zyb21faG9zdChsYXlvdXRfU0ZBX2hvc3QuZGF0YSgpLCBncm91cHMsIHN0cmVhbSk7CiAgICAgIGxheW91dF9TRkIuY29weV9mcm9tX2hvc3QobGF5b3V0X1NGQl9ob3N0LmRhdGEoKSwgZ3JvdXBzLCBzdHJlYW0pOwoKICAgICAgY3V0bGFzczo6S2VybmVsSGFyZHdhcmVJbmZvIGh3X2luZm87CiAgICAgIGh3X2luZm8uZGV2aWNlX2lkID0gZGV2aWNlX2lkOwogICAgICBod19pbmZvLnNtX2NvdW50ID0gY3V0bGFzczo6S2VybmVsSGFyZHdhcmVJbmZvOjpxdWVyeV9kZXZpY2VfbXVsdGlwcm9jZXNzb3JfY291bnQoaHdfaW5mby5kZXZpY2VfaWQpOwogICAgICBpZiBjb25zdGV4cHIgKHN0ZDo6aXNfc2FtZV92PEdlbW0sIEdlbW0xU00+KSB7CiAgICAgICAgaHdfaW5mby5jbHVzdGVyX3NoYXBlID0gZGltMygxLCAxLCAxKTsKICAgICAgICBod19pbmZvLmNsdXN0ZXJfc2hhcGVfZmFsbGJhY2sgPSBkaW0zKDEsIDEsIDEpOwogICAgICB9IGVsc2UgewogICAgICAgIGh3X2luZm8uY2x1c3Rlcl9zaGFwZSA9IGRpbTMoMiwgMSwgMSk7CiAgICAgICAgaHdfaW5mby5jbHVzdGVyX3NoYXBlX2ZhbGxiYWNrID0gZGltMygyLCAxLCAxKTsKICAgICAgfQoKICAgICAgdHlwZW5hbWUgR2VtbTo6QXJndW1lbnRzIGFyZ3VtZW50czsKICAgICAgZGVjbHR5cGUoYXJndW1lbnRzLmVwaWxvZ3VlLnRocmVhZCkgZnVzaW9uX2FyZ3M7CiAgICAgIGZ1c2lvbl9hcmdzLmFscGhhX3B0ciA9IG51bGxwdHI7CiAgICAgIGZ1c2lvbl9hcmdzLmJldGFfcHRyID0gbnVsbHB0cjsKICAgICAgZnVzaW9uX2FyZ3MuYWxwaGEgPSBFbGVtZW50QWNjdW11bGF0b3IoMSk7CiAgICAgIGZ1c2lvbl9hcmdzLmJldGEgPSBFbGVtZW50QWNjdW11bGF0b3IoMCk7CiAgICAgIGZ1c2lvbl9hcmdzLmFscGhhX3B0cl9hcnJheSA9IG51bGxwdHI7CiAgICAgIGZ1c2lvbl9hcmdzLmJldGFfcHRyX2FycmF5ID0gbnVsbHB0cjsKICAgICAgZnVzaW9uX2FyZ3MuZEFscGhhID0ge2N1dGU6Ol8we30sIGN1dGU6Ol8we30sIDB9OwogICAgICBmdXNpb25fYXJncy5kQmV0YSA9IHtjdXRlOjpfMHt9LCBjdXRlOjpfMHt9LCAwfTsKCiAgICAgIHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OlRpbGVTY2hlZHVsZXJBcmd1bWVudHMgc2NoZWR1bGVyOwogICAgICBzY2hlZHVsZXIubWF4X3N3aXp6bGVfc2l6ZSA9IDg7CiAgICAgIHNjaGVkdWxlci5yYXN0ZXJfb3JkZXIgPSBjdXRsYXNzOjpnZW1tOjprZXJuZWw6OmRldGFpbDo6UmFzdGVyT3JkZXJPcHRpb25zOjpIZXVyaXN0aWM7CgogICAgICBhcmd1bWVudHMgPSB0eXBlbmFtZSBHZW1tOjpBcmd1bWVudHMgewogICAgICAgIGN1dGxhc3M6OmdlbW06OkdlbW1Vbml2ZXJzYWxNb2RlOjprR3JvdXBlZCwKICAgICAgICB7Z3JvdXBzLCBwcm9ibGVtX3NpemVzX2RldmljZS5nZXQoKSwgbnVsbHB0cn0sCiAgICAgICAge3B0cl9BLmdldCgpLCBzdHJpZGVfQS5nZXQoKSwgcHRyX0IuZ2V0KCksIHN0cmlkZV9CLmdldCgpLAogICAgICAgICBwdHJfU0ZBLmdldCgpLCBsYXlvdXRfU0ZBLmdldCgpLCBwdHJfU0ZCLmdldCgpLCBsYXlvdXRfU0ZCLmdldCgpfSwKICAgICAgICB7ZnVzaW9uX2FyZ3MsIHB0cl9DLmdldCgpLCBzdHJpZGVfQy5nZXQoKSwgcHRyX0QuZ2V0KCksIHN0cmlkZV9ELmdldCgpfSwKICAgICAgICBod19pbmZvLCBzY2hlZHVsZXIKICAgICAgfTsKCiAgICAgIEdlbW0gZ2VtbTsKICAgICAgc2l6ZV90IHdvcmtzcGFjZV9zaXplID0gR2VtbTo6Z2V0X3dvcmtzcGFjZV9zaXplKGFyZ3VtZW50cyk7CiAgICAgIGlmICghd29ya3NwYWNlX3RlbnNvci5kZWZpbmVkKCkgfHwgY2FjaGVkX2RldmljZSAhPSBkZXZpY2VfaWQgfHwgd29ya3NwYWNlX3NpemVfY2FjaGVkIDwgd29ya3NwYWNlX3NpemUpIHsKICAgICAgICBhdXRvIG9wdHMgPSB0b3JjaDo6VGVuc29yT3B0aW9ucygpLmRldmljZSh0b3JjaDo6a0NVREEsIGRldmljZV9pZCkuZHR5cGUodG9yY2g6OmtVSW50OCk7CiAgICAgICAgd29ya3NwYWNlX3RlbnNvciA9IHRvcmNoOjplbXB0eSh7c3RhdGljX2Nhc3Q8bG9uZz4od29ya3NwYWNlX3NpemUpfSwgb3B0cyk7CiAgICAgICAgd29ya3NwYWNlX3NpemVfY2FjaGVkID0gd29ya3NwYWNlX3NpemU7CiAgICAgIH0KICAgICAgdm9pZCogd29ya3NwYWNlX3B0ciA9IHdvcmtzcGFjZV9zaXplID8gd29ya3NwYWNlX3RlbnNvci5kYXRhX3B0cigpIDogbnVsbHB0cjsKCiAgICAgIENVVExBU1NfQ0hFQ0soZ2VtbS5jYW5faW1wbGVtZW50KGFyZ3VtZW50cykpOwogICAgICBDVVRMQVNTX0NIRUNLKGdlbW0uaW5pdGlhbGl6ZShhcmd1bWVudHMsIHdvcmtzcGFjZV9wdHIsIHN0cmVhbSkpOwogICAgICBhdXRvIHJ1bl9zdGF0dXMgPSBnZW1tLnJ1bihzdHJlYW0sIG51bGxwdHIsIHRydWUpOwogICAgICBpZiAocnVuX3N0YXR1cyAhPSBjdXRsYXNzOjpTdGF0dXM6OmtTdWNjZXNzKSB7CiAgICAgICAgcnVuX3N0YXR1cyA9IGdlbW0ucnVuKHN0cmVhbSk7CiAgICAgIH0KICAgICAgQ1VUTEFTU19DSEVDSyhydW5fc3RhdHVzKTsKCiAgICAgIHJldHVybiBDOwogICAgfQoKICAgIHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+IGdyb3VwZWRfZ2VtbV8xc20oCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIEEsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIEIsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIEMsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIFNGQSwKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgU0ZCKSB7CiAgICAgIHJldHVybiBydW5fZ3JvdXBlZF9pbXBsPEdlbW0xU00+KEEsIEIsIEMsIFNGQSwgU0ZCKTsKICAgIH0KCiAgICBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiBncm91cGVkX2dlbW1fMnNtKAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBBLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBCLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBDLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBTRkEsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIFNGQikgewogICAgICByZXR1cm4gcnVuX2dyb3VwZWRfaW1wbDxHZW1tMlNNPihBLCBCLCBDLCBTRkEsIFNGQik7CiAgICB9CiAgICAK"+ _CU_B64 = "CiAgICAjaW5jbHVkZSA8dG9yY2gvZXh0ZW5zaW9uLmg+CiAgICAjaW5jbHVkZSA8QVRlbi9jdWRhL0NVREFDb250ZXh0Lmg+CiAgICAjaW5jbHVkZSA8YzEwL2N1ZGEvQ1VEQVN0cmVhbS5oPgogICAgI2luY2x1ZGUgPGMxMC9jdWRhL0NVREFHdWFyZC5oPgogICAgI2luY2x1ZGUgPHZlY3Rvcj4KICAgICNpbmNsdWRlIDxzdGRleGNlcHQ+CiAgICAjaW5jbHVkZSA8dHlwZV90cmFpdHM+CgogICAgI2lmZGVmIF9fQ1VEQV9OT19IQUxGX09QRVJBVE9SU19fCiAgICAjdW5kZWYgX19DVURBX05PX0hBTEZfT1BFUkFUT1JTX18KICAgICNlbmRpZgogICAgI2lmZGVmIF9fQ1VEQV9OT19IQUxGX0NPTlZFUlNJT05TX18KICAgICN1bmRlZiBfX0NVREFfTk9fSEFMRl9DT05WRVJTSU9OU19fCiAgICAjZW5kaWYKICAgICNpZmRlZiBfX0NVREFfTk9fSEFMRjJfT1BFUkFUT1JTX18KICAgICN1bmRlZiBfX0NVREFfTk9fSEFMRjJfT1BFUkFUT1JTX18KICAgICNlbmRpZgoKICAgICNpbmNsdWRlIDxjdWRhX3J1bnRpbWUuaD4KICAgICNpZiBkZWZpbmVkKF9fQ1VEQV9BUkNIX18pICYmICFkZWZpbmVkKENVVExBU1NfQVJDSF9NTUFfU00xMDBBX0VOQUJMRUQpCiAgICAjZGVmaW5lIENVVExBU1NfQVJDSF9NTUFfU00xMDBBX0VOQUJMRUQgMQogICAgI2VuZGlmCiAgICAjaW5jbHVkZSAiY3V0bGFzcy9jdXRsYXNzLmgiCiAgICAjaW5jbHVkZSAiY3V0ZS90ZW5zb3IuaHBwIgogICAgI2luY2x1ZGUgImN1dGxhc3MvdGVuc29yX3JlZi5oIgogICAgI2luY2x1ZGUgImN1dGxhc3MvZXBpbG9ndWUvY29sbGVjdGl2ZS9kZWZhdWx0X2VwaWxvZ3VlLmhwcCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2VwaWxvZ3VlL3RocmVhZC9saW5lYXJfY29tYmluYXRpb24uaCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2dlbW0vZGlzcGF0Y2hfcG9saWN5LmhwcCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2dlbW0vZ3JvdXBfYXJyYXlfcHJvYmxlbV9zaGFwZS5ocHAiCiAgICAjaW5jbHVkZSAiY3V0bGFzcy9nZW1tL2NvbGxlY3RpdmUvY29sbGVjdGl2ZV9idWlsZGVyLmhwcCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2VwaWxvZ3VlL2NvbGxlY3RpdmUvY29sbGVjdGl2ZV9idWlsZGVyLmhwcCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2dlbW0vZGV2aWNlL2dlbW1fdW5pdmVyc2FsX2FkYXB0ZXIuaCIKICAgICNpbmNsdWRlICJjdXRsYXNzL2dlbW0va2VybmVsL2dlbW1fdW5pdmVyc2FsLmhwcCIKICAgICNpbmNsdWRlICJjdXRsYXNzL3V0aWwvcGFja2VkX3N0cmlkZS5ocHAiCiAgICAjaW5jbHVkZSAiY3V0bGFzcy9rZXJuZWxfaGFyZHdhcmVfaW5mby5oIgogICAgI2luY2x1ZGUgImN1dGxhc3MvdXRpbC9kZXZpY2VfbWVtb3J5LmgiCiAgICAjaW5jbHVkZSAiY3V0bGFzcy9nZW1tL2tlcm5lbC90aWxlX3NjaGVkdWxlcl9wYXJhbXMuaCIKCiAgICAjZGVmaW5lIENVVExBU1NfQ0hFQ0soc3RhdHVzKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXAogICAgICBkbyB7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwKICAgICAgICBjdXRsYXNzOjpTdGF0dXMgX3N0YXR1cyA9IChzdGF0dXMpOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcCiAgICAgICAgaWYgKF9zdGF0dXMgIT0gY3V0bGFzczo6U3RhdHVzOjprU3VjY2VzcykgeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXAogICAgICAgICAgdGhyb3cgc3RkOjpydW50aW1lX2Vycm9yKCJDVVRMQVNTIGVycm9yIik7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwKICAgICAgICB9ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcCiAgICAgIH0gd2hpbGUgKDApCgogICAgI2RlZmluZSBDVURBX0NIRUNLKGV4cHIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXAogICAgICBkbyB7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwKICAgICAgICBjdWRhRXJyb3JfdCBfZXJyID0gKGV4cHIpOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcCiAgICAgICAgaWYgKF9lcnIgIT0gY3VkYVN1Y2Nlc3MpIHsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXAogICAgICAgICAgdGhyb3cgc3RkOjpydW50aW1lX2Vycm9yKGN1ZGFHZXRFcnJvclN0cmluZyhfZXJyKSk7ICAgICAgICAgICAgICAgICAgICAgICAgIFwKICAgICAgICB9ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcCiAgICAgIH0gd2hpbGUgKDApCgogICAgdXNpbmcgUHJvYmxlbVNoYXBlID0gY3V0bGFzczo6Z2VtbTo6R3JvdXBQcm9ibGVtU2hhcGU8Y3V0ZTo6U2hhcGU8aW50LGludCxpbnQ+PjsKICAgIHVzaW5nIEVsZW1lbnRJbnB1dCA9IGN1dGxhc3M6OmZsb2F0X2UybTFfdDsKICAgIHVzaW5nIEVsZW1lbnRTRiAgICA9IGN1dGxhc3M6OmZsb2F0X3VlNG0zX3Q7CiAgICB1c2luZyBFbGVtZW50QyAgICAgPSBjdXRsYXNzOjpoYWxmX3Q7CgogICAgdXNpbmcgRWxlbWVudEEgPSBjdXRsYXNzOjpudl9mbG9hdDRfdDxFbGVtZW50SW5wdXQ+OwogICAgdXNpbmcgTGF5b3V0QSAgPSBjdXRsYXNzOjpsYXlvdXQ6OlJvd01ham9yOwogICAgY29uc3RleHByIGludCBBbGlnbm1lbnRBICA9IDMyOwoKICAgIHVzaW5nIEVsZW1lbnRCID0gY3V0bGFzczo6bnZfZmxvYXQ0X3Q8RWxlbWVudElucHV0PjsKICAgIHVzaW5nIExheW91dEIgID0gY3V0bGFzczo6bGF5b3V0OjpDb2x1bW5NYWpvcjsKICAgIGNvbnN0ZXhwciBpbnQgQWxpZ25tZW50QiAgPSAzMjsKCiAgICB1c2luZyBFbGVtZW50RCA9IEVsZW1lbnRDOwogICAgdXNpbmcgTGF5b3V0QyAgPSBjdXRsYXNzOjpsYXlvdXQ6OlJvd01ham9yOwogICAgY29uc3RleHByIGludCBBbGlnbm1lbnRDICA9IDEyOCAvIGN1dGxhc3M6OnNpemVvZl9iaXRzPEVsZW1lbnRDPjo6dmFsdWU7CiAgICBjb25zdGV4cHIgaW50IEFsaWdubWVudEQgID0gMTI4IC8gY3V0bGFzczo6c2l6ZW9mX2JpdHM8RWxlbWVudEQ+Ojp2YWx1ZTsKICAgIHVzaW5nIEVsZW1lbnRBY2N1bXVsYXRvciAgPSBmbG9hdDsKCiAgICB1c2luZyBBcmNoVGFnID0gY3V0bGFzczo6YXJjaDo6U20xMDA7CiAgICB1c2luZyBPcGVyYXRvckNsYXNzID0gY3V0bGFzczo6YXJjaDo6T3BDbGFzc0Jsb2NrU2NhbGVkVGVuc29yT3A7CiAgICB1c2luZyBTdGFnZUNvdW50VHlwZSA9IGN1dGxhc3M6OmdlbW06OmNvbGxlY3RpdmU6OlN0YWdlQ291bnRBdXRvOwogICAgdXNpbmcgQ2x1c3RlclNoYXBlID0gY3V0ZTo6U2hhcGU8aW50MzJfdCxpbnQzMl90LGN1dGU6Ol8xPjsKCiAgICBzdHJ1Y3QgTU1BMVNNQ29uZmlnIHsKICAgICAgdXNpbmcgTW1hVGlsZVNoYXBlICAgICA9IGN1dGU6OlNoYXBlPGN1dGU6Ol8xMjgsY3V0ZTo6XzI1NixjdXRlOjpfMjU2PjsKICAgICAgdXNpbmcgS2VybmVsU2NoZWR1bGUgICA9IGN1dGxhc3M6OmdlbW06Oktlcm5lbFB0ckFycmF5VG1hV2FycFNwZWNpYWxpemVkMVNtTnZmNFNtMTAwOwogICAgICB1c2luZyBFcGlsb2d1ZVNjaGVkdWxlID0gY3V0bGFzczo6ZXBpbG9ndWU6OlB0ckFycmF5VG1hV2FycFNwZWNpYWxpemVkMVNtOwogICAgfTsKCiAgICBzdHJ1Y3QgTU1BMlNNQ29uZmlnIHsKICAgICAgdXNpbmcgTW1hVGlsZVNoYXBlICAgICA9IGN1dGU6OlNoYXBlPGN1dGU6Ol8yNTYsY3V0ZTo6XzI1NixjdXRlOjpfMjU2PjsKICAgICAgdXNpbmcgS2VybmVsU2NoZWR1bGUgICA9IGN1dGxhc3M6OmdlbW06Oktlcm5lbFB0ckFycmF5VG1hV2FycFNwZWNpYWxpemVkMlNtTnZmNFNtMTAwOwogICAgICB1c2luZyBFcGlsb2d1ZVNjaGVkdWxlID0gY3V0bGFzczo6ZXBpbG9ndWU6OlB0ckFycmF5VG1hV2FycFNwZWNpYWxpemVkMlNtOwogICAgfTsKCiAgICB1c2luZyBDb2xsZWN0aXZlRXBpbG9ndWUxU00gPSB0eXBlbmFtZSBjdXRsYXNzOjplcGlsb2d1ZTo6Y29sbGVjdGl2ZTo6Q29sbGVjdGl2ZUJ1aWxkZXI8CiAgICAgICAgQXJjaFRhZywgT3BlcmF0b3JDbGFzcywKICAgICAgICB0eXBlbmFtZSBNTUExU01Db25maWc6Ok1tYVRpbGVTaGFwZSwgQ2x1c3RlclNoYXBlLAogICAgICAgIGN1dGU6OlNoYXBlPGN1dGU6Ol8xMjgsY3V0ZTo6XzY0PiwKICAgICAgICBFbGVtZW50QWNjdW11bGF0b3IsIEVsZW1lbnRBY2N1bXVsYXRvciwKICAgICAgICBFbGVtZW50QywgTGF5b3V0QyAqLCBBbGlnbm1lbnRDLAogICAgICAgIEVsZW1lbnRELCBMYXlvdXRDICosIEFsaWdubWVudEQsCiAgICAgICAgdHlwZW5hbWUgTU1BMVNNQ29uZmlnOjpFcGlsb2d1ZVNjaGVkdWxlCiAgICA+OjpDb2xsZWN0aXZlT3A7CgogICAgdXNpbmcgQ29sbGVjdGl2ZU1haW5sb29wMVNNID0gdHlwZW5hbWUgY3V0bGFzczo6Z2VtbTo6Y29sbGVjdGl2ZTo6Q29sbGVjdGl2ZUJ1aWxkZXI8CiAgICAgIEFyY2hUYWcsIE9wZXJhdG9yQ2xhc3MsCiAgICAgIEVsZW1lbnRBLCBMYXlvdXRBICosIEFsaWdubWVudEEsCiAgICAgIEVsZW1lbnRCLCBMYXlvdXRCICosIEFsaWdubWVudEIsCiAgICAgIEVsZW1lbnRBY2N1bXVsYXRvciwKICAgICAgdHlwZW5hbWUgTU1BMVNNQ29uZmlnOjpNbWFUaWxlU2hhcGUsIENsdXN0ZXJTaGFwZSwKICAgICAgY3V0bGFzczo6Z2VtbTo6Y29sbGVjdGl2ZTo6U3RhZ2VDb3VudEF1dG9DYXJ2ZW91dDwKICAgICAgICBzdGF0aWNfY2FzdDxpbnQ+KHNpemVvZih0eXBlbmFtZSBDb2xsZWN0aXZlRXBpbG9ndWUxU006OlNoYXJlZFN0b3JhZ2UpKT4sCiAgICAgIHR5cGVuYW1lIE1NQTFTTUNvbmZpZzo6S2VybmVsU2NoZWR1bGUKICAgID46OkNvbGxlY3RpdmVPcDsKCiAgICB1c2luZyBHZW1tS2VybmVsMVNNID0gY3V0bGFzczo6Z2VtbTo6a2VybmVsOjpHZW1tVW5pdmVyc2FsPAogICAgICAgIFByb2JsZW1TaGFwZSwKICAgICAgICBDb2xsZWN0aXZlTWFpbmxvb3AxU00sCiAgICAgICAgQ29sbGVjdGl2ZUVwaWxvZ3VlMVNNCiAgICA+OwogICAgdXNpbmcgR2VtbTFTTSA9IGN1dGxhc3M6OmdlbW06OmRldmljZTo6R2VtbVVuaXZlcnNhbEFkYXB0ZXI8R2VtbUtlcm5lbDFTTT47CgogICAgdXNpbmcgQ29sbGVjdGl2ZUVwaWxvZ3VlMlNNID0gdHlwZW5hbWUgY3V0bGFzczo6ZXBpbG9ndWU6OmNvbGxlY3RpdmU6OkNvbGxlY3RpdmVCdWlsZGVyPAogICAgICAgIEFyY2hUYWcsIE9wZXJhdG9yQ2xhc3MsCiAgICAgICAgdHlwZW5hbWUgTU1BMlNNQ29uZmlnOjpNbWFUaWxlU2hhcGUsIENsdXN0ZXJTaGFwZSwKICAgICAgICBjdXRlOjpTaGFwZTxjdXRlOjpfMTI4LGN1dGU6Ol82ND4sCiAgICAgICAgRWxlbWVudEFjY3VtdWxhdG9yLCBFbGVtZW50QWNjdW11bGF0b3IsCiAgICAgICAgRWxlbWVudEMsIExheW91dEMgKiwgQWxpZ25tZW50QywKICAgICAgICBFbGVtZW50RCwgTGF5b3V0QyAqLCBBbGlnbm1lbnRELAogICAgICAgIHR5cGVuYW1lIE1NQTJTTUNvbmZpZzo6RXBpbG9ndWVTY2hlZHVsZQogICAgPjo6Q29sbGVjdGl2ZU9wOwoKICAgIHVzaW5nIENvbGxlY3RpdmVNYWlubG9vcDJTTSA9IHR5cGVuYW1lIGN1dGxhc3M6OmdlbW06OmNvbGxlY3RpdmU6OkNvbGxlY3RpdmVCdWlsZGVyPAogICAgICBBcmNoVGFnLCBPcGVyYXRvckNsYXNzLAogICAgICBFbGVtZW50QSwgTGF5b3V0QSAqLCBBbGlnbm1lbnRBLAogICAgICBFbGVtZW50QiwgTGF5b3V0QiAqLCBBbGlnbm1lbnRCLAogICAgICBFbGVtZW50QWNjdW11bGF0b3IsCiAgICAgIHR5cGVuYW1lIE1NQTJTTUNvbmZpZzo6TW1hVGlsZVNoYXBlLCBDbHVzdGVyU2hhcGUsCiAgICAgIGN1dGxhc3M6OmdlbW06OmNvbGxlY3RpdmU6OlN0YWdlQ291bnRBdXRvQ2FydmVvdXQ8CiAgICAgICAgc3RhdGljX2Nhc3Q8aW50PihzaXplb2YodHlwZW5hbWUgQ29sbGVjdGl2ZUVwaWxvZ3VlMlNNOjpTaGFyZWRTdG9yYWdlKSk+LAogICAgICB0eXBlbmFtZSBNTUEyU01Db25maWc6Oktlcm5lbFNjaGVkdWxlCiAgICA+OjpDb2xsZWN0aXZlT3A7CgogICAgdXNpbmcgR2VtbUtlcm5lbDJTTSA9IGN1dGxhc3M6OmdlbW06Omtlcm5lbDo6R2VtbVVuaXZlcnNhbDwKICAgICAgICBQcm9ibGVtU2hhcGUsCiAgICAgICAgQ29sbGVjdGl2ZU1haW5sb29wMlNNLAogICAgICAgIENvbGxlY3RpdmVFcGlsb2d1ZTJTTQogICAgPjsKICAgIHVzaW5nIEdlbW0yU00gPSBjdXRsYXNzOjpnZW1tOjpkZXZpY2U6OkdlbW1Vbml2ZXJzYWxBZGFwdGVyPEdlbW1LZXJuZWwyU00+OwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUPgogICAgc3RydWN0IFBpbm5lZEhvc3RCdWZmZXIgewogICAgICBUKiBwdHIgPSBudWxscHRyOwogICAgICBzaXplX3QgY291bnQgPSAwOwoKICAgICAgUGlubmVkSG9zdEJ1ZmZlcigpID0gZGVmYXVsdDsKICAgICAgZXhwbGljaXQgUGlubmVkSG9zdEJ1ZmZlcihzaXplX3QgbikgeyBhbGxvY2F0ZShuKTsgfQoKICAgICAgdm9pZCBhbGxvY2F0ZShzaXplX3QgbikgewogICAgICAgIGlmIChwdHIgJiYgY291bnQgPj0gbikgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICByZWxlYXNlKCk7CiAgICAgICAgY291bnQgPSBuOwogICAgICAgIENVREFfQ0hFQ0soY3VkYUhvc3RBbGxvYyhyZWludGVycHJldF9jYXN0PHZvaWQqKj4oJnB0ciksIG4gKiBzaXplb2YoVCksIGN1ZGFIb3N0QWxsb2NQb3J0YWJsZSkpOwogICAgICB9CgogICAgICB2b2lkIHJlbGVhc2UoKSB7CiAgICAgICAgaWYgKHB0cikgewogICAgICAgICAgY3VkYUZyZWVIb3N0KHB0cik7CiAgICAgICAgICBwdHIgPSBudWxscHRyOwogICAgICAgICAgY291bnQgPSAwOwogICAgICAgIH0KICAgICAgfQoKICAgICAgflBpbm5lZEhvc3RCdWZmZXIoKSB7IHJlbGVhc2UoKTsgfQoKICAgICAgVCogZGF0YSgpIGNvbnN0IHsgcmV0dXJuIHB0cjsgfQogICAgICBUJiBvcGVyYXRvcltdKHNpemVfdCBpZHgpIHsgcmV0dXJuIHB0cltpZHhdOyB9CiAgICB9OwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUPgogICAgc3RydWN0IERldmljZUJ1ZmZlciB7CiAgICAgIFQqIHB0ciA9IG51bGxwdHI7CiAgICAgIHNpemVfdCBjb3VudCA9IDA7CgogICAgICBEZXZpY2VCdWZmZXIoKSA9IGRlZmF1bHQ7CiAgICAgIGV4cGxpY2l0IERldmljZUJ1ZmZlcihzaXplX3QgbikgeyBhbGxvY2F0ZShuKTsgfQoKICAgICAgdm9pZCBhbGxvY2F0ZShzaXplX3QgbikgewogICAgICAgIGlmIChwdHIgJiYgY291bnQgPj0gbikgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICByZWxlYXNlKCk7CiAgICAgICAgY291bnQgPSBuOwogICAgICAgIENVREFfQ0hFQ0soY3VkYU1hbGxvYyhyZWludGVycHJldF9jYXN0PHZvaWQqKj4oJnB0ciksIG4gKiBzaXplb2YoVCkpKTsKICAgICAgfQoKICAgICAgdm9pZCByZWxlYXNlKCkgewogICAgICAgIGlmIChwdHIpIHsKICAgICAgICAgIGN1ZGFGcmVlKHB0cik7CiAgICAgICAgICBwdHIgPSBudWxscHRyOwogICAgICAgICAgY291bnQgPSAwOwogICAgICAgIH0KICAgICAgfQoKICAgICAgfkRldmljZUJ1ZmZlcigpIHsgcmVsZWFzZSgpOyB9CgogICAgICBUKiBnZXQoKSBjb25zdCB7IHJldHVybiBwdHI7IH0KCiAgICAgIHZvaWQgY29weV9mcm9tX2hvc3QoY29uc3QgVCogaG9zdCwgc2l6ZV90IG4sIGN1ZGFTdHJlYW1fdCBzdHJlYW0pIHsKICAgICAgICBDVURBX0NIRUNLKGN1ZGFNZW1jcHlBc3luYyhwdHIsIGhvc3QsIG4gKiBzaXplb2YoVCksIGN1ZGFNZW1jcHlIb3N0VG9EZXZpY2UsIHN0cmVhbSkpOwogICAgICB9CiAgICB9OwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBHZW1tPgogICAgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4gcnVuX2dyb3VwZWRfaW1wbCgKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgQSwKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgQiwKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgQywKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgU0ZBLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBTRkIpIHsKCiAgICAgIFRPUkNIX0NIRUNLKEEuc2l6ZSgpID09IEIuc2l6ZSgpLCAiQS9CIHNpemUgbWlzbWF0Y2giKTsKICAgICAgVE9SQ0hfQ0hFQ0soQS5zaXplKCkgPT0gQy5zaXplKCksICJBL0Mgc2l6ZSBtaXNtYXRjaCIpOwogICAgICBUT1JDSF9DSEVDSyhBLnNpemUoKSA9PSBTRkEuc2l6ZSgpLCAiQS9TRkEgc2l6ZSBtaXNtYXRjaCIpOwogICAgICBUT1JDSF9DSEVDSyhBLnNpemUoKSA9PSBTRkIuc2l6ZSgpLCAiQS9TRkIgc2l6ZSBtaXNtYXRjaCIpOwogICAgICBjb25zdCBpbnQzMl90IGdyb3VwcyA9IHN0YXRpY19jYXN0PGludDMyX3Q+KEEuc2l6ZSgpKTsKICAgICAgVE9SQ0hfQ0hFQ0soZ3JvdXBzID4gMCwgIk5vIGdyb3VwcyIpOwoKICAgICAgaW50IGRldmljZV9pZCA9IEFbMF0uZ2V0X2RldmljZSgpOwogICAgICBjMTA6OmN1ZGE6OkNVREFHdWFyZCBkZXZpY2VfZ3VhcmQoZGV2aWNlX2lkKTsKCiAgICAgIHVzaW5nIFN0cmlkZUEgPSB0eXBlbmFtZSBHZW1tOjpHZW1tS2VybmVsOjpJbnRlcm5hbFN0cmlkZUE7CiAgICAgIHVzaW5nIFN0cmlkZUIgPSB0eXBlbmFtZSBHZW1tOjpHZW1tS2VybmVsOjpJbnRlcm5hbFN0cmlkZUI7CiAgICAgIHVzaW5nIFN0cmlkZUMgPSB0eXBlbmFtZSBHZW1tOjpHZW1tS2VybmVsOjpJbnRlcm5hbFN0cmlkZUM7CiAgICAgIHVzaW5nIFN0cmlkZUQgPSB0eXBlbmFtZSBHZW1tOjpHZW1tS2VybmVsOjpJbnRlcm5hbFN0cmlkZUQ7CiAgICAgIHVzaW5nIExheW91dFNGQSA9IHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkNvbGxlY3RpdmVNYWlubG9vcDo6SW50ZXJuYWxMYXlvdXRTRkE7CiAgICAgIHVzaW5nIExheW91dFNGQiA9IHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkNvbGxlY3RpdmVNYWlubG9vcDo6SW50ZXJuYWxMYXlvdXRTRkI7CiAgICAgIHVzaW5nIFNtMXh4QmxrU2NhbGVkQ29uZmlnID0gdHlwZW5hbWUgR2VtbTo6R2VtbUtlcm5lbDo6Q29sbGVjdGl2ZU1haW5sb29wOjpTbTF4eEJsa1NjYWxlZENvbmZpZzsKCiAgICAgIHN0YXRpYyBzaXplX3QgY2FwYWNpdHkgPSAwOwogICAgICBzdGF0aWMgaW50IGNhY2hlZF9kZXZpY2UgPSAtMTsKICAgICAgc3RhdGljIFBpbm5lZEhvc3RCdWZmZXI8dHlwZW5hbWUgR2VtbTo6RWxlbWVudEEgY29uc3QqPiBwdHJfQV9ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjx0eXBlbmFtZSBHZW1tOjpFbGVtZW50QiBjb25zdCo+IHB0cl9CX2hvc3Q7CiAgICAgIHN0YXRpYyBQaW5uZWRIb3N0QnVmZmVyPHR5cGVuYW1lIEdlbW06OkVsZW1lbnRDIGNvbnN0Kj4gcHRyX0NfaG9zdDsKICAgICAgc3RhdGljIFBpbm5lZEhvc3RCdWZmZXI8dHlwZW5hbWUgR2VtbTo6RXBpbG9ndWVPdXRwdXRPcDo6RWxlbWVudE91dHB1dCo+IHB0cl9EX2hvc3Q7CiAgICAgIHN0YXRpYyBQaW5uZWRIb3N0QnVmZmVyPHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkVsZW1lbnRTRiBjb25zdCo+IHB0cl9TRkFfaG9zdDsKICAgICAgc3RhdGljIFBpbm5lZEhvc3RCdWZmZXI8dHlwZW5hbWUgR2VtbTo6R2VtbUtlcm5lbDo6RWxlbWVudFNGIGNvbnN0Kj4gcHRyX1NGQl9ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjxTdHJpZGVBPiBzdHJpZGVfQV9ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjxTdHJpZGVCPiBzdHJpZGVfQl9ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjxTdHJpZGVDPiBzdHJpZGVfQ19ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjxTdHJpZGVEPiBzdHJpZGVfRF9ob3N0OwogICAgICBzdGF0aWMgUGlubmVkSG9zdEJ1ZmZlcjxMYXlvdXRTRkE+IGxheW91dF9TRkFfaG9zdDsKICAgICAgc3RhdGljIFBpbm5lZEhvc3RCdWZmZXI8TGF5b3V0U0ZCPiBsYXlvdXRfU0ZCX2hvc3Q7CiAgICAgIHN0YXRpYyBQaW5uZWRIb3N0QnVmZmVyPHR5cGVuYW1lIFByb2JsZW1TaGFwZTo6VW5kZXJseWluZ1Byb2JsZW1TaGFwZT4gcHJvYmxlbV9zaXplc19ob3N0OwoKICAgICAgc3RhdGljIERldmljZUJ1ZmZlcjx0eXBlbmFtZSBQcm9ibGVtU2hhcGU6OlVuZGVybHlpbmdQcm9ibGVtU2hhcGU+IHByb2JsZW1fc2l6ZXNfZGV2aWNlOwogICAgICBzdGF0aWMgRGV2aWNlQnVmZmVyPHR5cGVuYW1lIEdlbW06OkVsZW1lbnRBIGNvbnN0Kj4gcHRyX0E7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8dHlwZW5hbWUgR2VtbTo6RWxlbWVudEIgY29uc3QqPiBwdHJfQjsKICAgICAgc3RhdGljIERldmljZUJ1ZmZlcjx0eXBlbmFtZSBHZW1tOjpHZW1tS2VybmVsOjpFbGVtZW50U0YgY29uc3QqPiBwdHJfU0ZBOwogICAgICBzdGF0aWMgRGV2aWNlQnVmZmVyPHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkVsZW1lbnRTRiBjb25zdCo+IHB0cl9TRkI7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8dHlwZW5hbWUgR2VtbTo6RWxlbWVudEMgY29uc3QqPiBwdHJfQzsKICAgICAgc3RhdGljIERldmljZUJ1ZmZlcjx0eXBlbmFtZSBHZW1tOjpFcGlsb2d1ZU91dHB1dE9wOjpFbGVtZW50T3V0cHV0Kj4gcHRyX0Q7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8U3RyaWRlQT4gc3RyaWRlX0E7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8U3RyaWRlQj4gc3RyaWRlX0I7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8U3RyaWRlQz4gc3RyaWRlX0M7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8U3RyaWRlRD4gc3RyaWRlX0Q7CiAgICAgIHN0YXRpYyBEZXZpY2VCdWZmZXI8TGF5b3V0U0ZBPiBsYXlvdXRfU0ZBOwogICAgICBzdGF0aWMgRGV2aWNlQnVmZmVyPExheW91dFNGQj4gbGF5b3V0X1NGQjsKICAgICAgc3RhdGljIHNpemVfdCB3b3Jrc3BhY2Vfc2l6ZV9jYWNoZWQgPSAwOwogICAgICBzdGF0aWMgdG9yY2g6OlRlbnNvciB3b3Jrc3BhY2VfdGVuc29yOwoKICAgICAgaWYgKGNhY2hlZF9kZXZpY2UgIT0gZGV2aWNlX2lkIHx8IGNhcGFjaXR5IDwgc3RhdGljX2Nhc3Q8c2l6ZV90Pihncm91cHMpKSB7CiAgICAgICAgY2FjaGVkX2RldmljZSA9IGRldmljZV9pZDsKICAgICAgICBjYXBhY2l0eSA9IHN0YXRpY19jYXN0PHNpemVfdD4oZ3JvdXBzKTsKICAgICAgICBwdHJfQV9ob3N0LmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX0JfaG9zdC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHB0cl9DX2hvc3QuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBwdHJfRF9ob3N0LmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX1NGQV9ob3N0LmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX1NGQl9ob3N0LmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgc3RyaWRlX0FfaG9zdC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHN0cmlkZV9CX2hvc3QuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBzdHJpZGVfQ19ob3N0LmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgc3RyaWRlX0RfaG9zdC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIGxheW91dF9TRkFfaG9zdC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIGxheW91dF9TRkJfaG9zdC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHByb2JsZW1fc2l6ZXNfaG9zdC5hbGxvY2F0ZShncm91cHMpOwoKICAgICAgICBwcm9ibGVtX3NpemVzX2RldmljZS5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHB0cl9BLmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX0IuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBwdHJfU0ZBLmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX1NGQi5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHB0cl9DLmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgcHRyX0QuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBzdHJpZGVfQS5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIHN0cmlkZV9CLmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgICAgc3RyaWRlX0MuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBzdHJpZGVfRC5hbGxvY2F0ZShncm91cHMpOwogICAgICAgIGxheW91dF9TRkEuYWxsb2NhdGUoZ3JvdXBzKTsKICAgICAgICBsYXlvdXRfU0ZCLmFsbG9jYXRlKGdyb3Vwcyk7CiAgICAgIH0KCiAgICAgIGZvciAoaW50MzJfdCBpID0gMDsgaSA8IGdyb3VwczsgKytpKSB7CiAgICAgICAgVE9SQ0hfQ0hFQ0soQVtpXS5pc19jdWRhKCksICJBIG11c3QgYmUgQ1VEQSIpOwogICAgICAgIFRPUkNIX0NIRUNLKEJbaV0uaXNfY3VkYSgpLCAiQiBtdXN0IGJlIENVREEiKTsKICAgICAgICBUT1JDSF9DSEVDSyhDW2ldLmlzX2N1ZGEoKSwgIkMgbXVzdCBiZSBDVURBIik7CiAgICAgICAgVE9SQ0hfQ0hFQ0soU0ZBW2ldLmlzX2N1ZGEoKSwgIlNGQSBtdXN0IGJlIENVREEiKTsKICAgICAgICBUT1JDSF9DSEVDSyhTRkJbaV0uaXNfY3VkYSgpLCAiU0ZCIG11c3QgYmUgQ1VEQSIpOwoKICAgICAgICBpbnQzMl90IG0gPSBzdGF0aWNfY2FzdDxpbnQzMl90PihBW2ldLnNpemUoMCkpOwogICAgICAgIGludDMyX3Qga19wYWNrZWQgPSBzdGF0aWNfY2FzdDxpbnQzMl90PihBW2ldLnNpemUoMSkpOwogICAgICAgIGludDMyX3QgayA9IGtfcGFja2VkICogMjsKICAgICAgICBpbnQzMl90IG4gPSBzdGF0aWNfY2FzdDxpbnQzMl90PihCW2ldLnNpemUoMCkpOwogICAgICAgIFRPUkNIX0NIRUNLKEJbaV0uc2l6ZSgxKSAqIDIgPT0gaywgIksgbWlzbWF0Y2giKTsKICAgICAgICBUT1JDSF9DSEVDSyhDW2ldLnNpemUoMCkgPT0gbSAmJiBDW2ldLnNpemUoMSkgPT0gbiwgIkMgc2hhcGUgbWlzbWF0Y2giKTsKCiAgICAgICAgcHJvYmxlbV9zaXplc19ob3N0W2ldID0gY3V0ZTo6bWFrZV9zaGFwZShtLCBuLCBrKTsKICAgICAgICBzdHJpZGVfQV9ob3N0W2ldID0gY3V0bGFzczo6bWFrZV9jdXRlX3BhY2tlZF9zdHJpZGUoU3RyaWRlQXt9LCB7bSwgaywgMX0pOwogICAgICAgIHN0cmlkZV9CX2hvc3RbaV0gPSBjdXRsYXNzOjptYWtlX2N1dGVfcGFja2VkX3N0cmlkZShTdHJpZGVCe30sIHtuLCBrLCAxfSk7CiAgICAgICAgc3RyaWRlX0NfaG9zdFtpXSA9IGN1dGxhc3M6Om1ha2VfY3V0ZV9wYWNrZWRfc3RyaWRlKFN0cmlkZUN7fSwge20sIG4sIDF9KTsKICAgICAgICBzdHJpZGVfRF9ob3N0W2ldID0gY3V0bGFzczo6bWFrZV9jdXRlX3BhY2tlZF9zdHJpZGUoU3RyaWRlRHt9LCB7bSwgbiwgMX0pOwogICAgICAgIGxheW91dF9TRkFfaG9zdFtpXSA9IFNtMXh4QmxrU2NhbGVkQ29uZmlnOjp0aWxlX2F0b21fdG9fc2hhcGVfU0ZBKGN1dGU6Om1ha2Vfc2hhcGUobSwgbiwgaywgMSkpOwogICAgICAgIGxheW91dF9TRkJfaG9zdFtpXSA9IFNtMXh4QmxrU2NhbGVkQ29uZmlnOjp0aWxlX2F0b21fdG9fc2hhcGVfU0ZCKGN1dGU6Om1ha2Vfc2hhcGUobSwgbiwgaywgMSkpOwoKICAgICAgICBwdHJfQV9ob3N0W2ldID0gcmVpbnRlcnByZXRfY2FzdDx0eXBlbmFtZSBHZW1tOjpFbGVtZW50QSBjb25zdCo+KEFbaV0uZGF0YV9wdHIoKSk7CiAgICAgICAgcHRyX0JfaG9zdFtpXSA9IHJlaW50ZXJwcmV0X2Nhc3Q8dHlwZW5hbWUgR2VtbTo6RWxlbWVudEIgY29uc3QqPihCW2ldLmRhdGFfcHRyKCkpOwogICAgICAgIHB0cl9DX2hvc3RbaV0gPSByZWludGVycHJldF9jYXN0PHR5cGVuYW1lIEdlbW06OkVsZW1lbnRDIGNvbnN0Kj4oQ1tpXS5kYXRhX3B0cigpKTsKICAgICAgICBwdHJfRF9ob3N0W2ldID0gcmVpbnRlcnByZXRfY2FzdDx0eXBlbmFtZSBHZW1tOjpFcGlsb2d1ZU91dHB1dE9wOjpFbGVtZW50T3V0cHV0Kj4oQ1tpXS5kYXRhX3B0cigpKTsKICAgICAgICBwdHJfU0ZBX2hvc3RbaV0gPSByZWludGVycHJldF9jYXN0PHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkVsZW1lbnRTRiBjb25zdCo+KFNGQVtpXS5kYXRhX3B0cigpKTsKICAgICAgICBwdHJfU0ZCX2hvc3RbaV0gPSByZWludGVycHJldF9jYXN0PHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OkVsZW1lbnRTRiBjb25zdCo+KFNGQltpXS5kYXRhX3B0cigpKTsKICAgICAgfQoKICAgICAgYXV0byBzdHJlYW1fb2JqID0gYzEwOjpjdWRhOjpnZXRDdXJyZW50Q1VEQVN0cmVhbShkZXZpY2VfaWQpOwogICAgICBjMTA6OmN1ZGE6OkNVREFTdHJlYW1HdWFyZCBzdHJlYW1fZ3VhcmQoc3RyZWFtX29iaik7CiAgICAgIGN1ZGFTdHJlYW1fdCBzdHJlYW0gPSBzdHJlYW1fb2JqLnN0cmVhbSgpOwogICAgICBwcm9ibGVtX3NpemVzX2RldmljZS5jb3B5X2Zyb21faG9zdChwcm9ibGVtX3NpemVzX2hvc3QuZGF0YSgpLCBncm91cHMsIHN0cmVhbSk7CiAgICAgIHB0cl9BLmNvcHlfZnJvbV9ob3N0KHB0cl9BX2hvc3QuZGF0YSgpLCBncm91cHMsIHN0cmVhbSk7CiAgICAgIHB0cl9CLmNvcHlfZnJvbV9ob3N0KHB0cl9CX2hvc3QuZGF0YSgpLCBncm91cHMsIHN0cmVhbSk7CiAgICAgIHB0cl9TRkEuY29weV9mcm9tX2hvc3QocHRyX1NGQV9ob3N0LmRhdGEoKSwgZ3JvdXBzLCBzdHJlYW0pOwogICAgICBwdHJfU0ZCLmNvcHlfZnJvbV9ob3N0KHB0cl9TRkJfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgcHRyX0MuY29weV9mcm9tX2hvc3QocHRyX0NfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgcHRyX0QuY29weV9mcm9tX2hvc3QocHRyX0RfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgc3RyaWRlX0EuY29weV9mcm9tX2hvc3Qoc3RyaWRlX0FfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgc3RyaWRlX0IuY29weV9mcm9tX2hvc3Qoc3RyaWRlX0JfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgc3RyaWRlX0MuY29weV9mcm9tX2hvc3Qoc3RyaWRlX0NfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgc3RyaWRlX0QuY29weV9mcm9tX2hvc3Qoc3RyaWRlX0RfaG9zdC5kYXRhKCksIGdyb3Vwcywgc3RyZWFtKTsKICAgICAgbGF5b3V0X1NGQS5jb3B5X2Zyb21faG9zdChsYXlvdXRfU0ZBX2hvc3QuZGF0YSgpLCBncm91cHMsIHN0cmVhbSk7CiAgICAgIGxheW91dF9TRkIuY29weV9mcm9tX2hvc3QobGF5b3V0X1NGQl9ob3N0LmRhdGEoKSwgZ3JvdXBzLCBzdHJlYW0pOwoKICAgICAgY3V0bGFzczo6S2VybmVsSGFyZHdhcmVJbmZvIGh3X2luZm87CiAgICAgIGh3X2luZm8uZGV2aWNlX2lkID0gZGV2aWNlX2lkOwogICAgICBod19pbmZvLnNtX2NvdW50ID0gY3V0bGFzczo6S2VybmVsSGFyZHdhcmVJbmZvOjpxdWVyeV9kZXZpY2VfbXVsdGlwcm9jZXNzb3JfY291bnQoaHdfaW5mby5kZXZpY2VfaWQpOwogICAgICBpZiBjb25zdGV4cHIgKHN0ZDo6aXNfc2FtZV92PEdlbW0sIEdlbW0xU00+KSB7CiAgICAgICAgaHdfaW5mby5jbHVzdGVyX3NoYXBlID0gZGltMygxLCAxLCAxKTsKICAgICAgICBod19pbmZvLmNsdXN0ZXJfc2hhcGVfZmFsbGJhY2sgPSBkaW0zKDEsIDEsIDEpOwogICAgICB9IGVsc2UgewogICAgICAgIGh3X2luZm8uY2x1c3Rlcl9zaGFwZSA9IGRpbTMoMiwgMSwgMSk7CiAgICAgICAgaHdfaW5mby5jbHVzdGVyX3NoYXBlX2ZhbGxiYWNrID0gZGltMygyLCAxLCAxKTsKICAgICAgfQoKICAgICAgdHlwZW5hbWUgR2VtbTo6QXJndW1lbnRzIGFyZ3VtZW50czsKICAgICAgZGVjbHR5cGUoYXJndW1lbnRzLmVwaWxvZ3VlLnRocmVhZCkgZnVzaW9uX2FyZ3M7CiAgICAgIGZ1c2lvbl9hcmdzLmFscGhhX3B0ciA9IG51bGxwdHI7CiAgICAgIGZ1c2lvbl9hcmdzLmJldGFfcHRyID0gbnVsbHB0cjsKICAgICAgZnVzaW9uX2FyZ3MuYWxwaGEgPSBFbGVtZW50QWNjdW11bGF0b3IoMSk7CiAgICAgIGZ1c2lvbl9hcmdzLmJldGEgPSBFbGVtZW50QWNjdW11bGF0b3IoMCk7CiAgICAgIGZ1c2lvbl9hcmdzLmFscGhhX3B0cl9hcnJheSA9IG51bGxwdHI7CiAgICAgIGZ1c2lvbl9hcmdzLmJldGFfcHRyX2FycmF5ID0gbnVsbHB0cjsKICAgICAgZnVzaW9uX2FyZ3MuZEFscGhhID0ge2N1dGU6Ol8we30sIGN1dGU6Ol8we30sIDB9OwogICAgICBmdXNpb25fYXJncy5kQmV0YSA9IHtjdXRlOjpfMHt9LCBjdXRlOjpfMHt9LCAwfTsKCiAgICAgIHR5cGVuYW1lIEdlbW06OkdlbW1LZXJuZWw6OlRpbGVTY2hlZHVsZXJBcmd1bWVudHMgc2NoZWR1bGVyOwogICAgICBzY2hlZHVsZXIubWF4X3N3aXp6bGVfc2l6ZSA9IDg7CiAgICAgIHNjaGVkdWxlci5yYXN0ZXJfb3JkZXIgPSBjdXRsYXNzOjpnZW1tOjprZXJuZWw6OmRldGFpbDo6UmFzdGVyT3JkZXJPcHRpb25zOjpBbG9uZ047CgogICAgICBhcmd1bWVudHMgPSB0eXBlbmFtZSBHZW1tOjpBcmd1bWVudHMgewogICAgICAgIGN1dGxhc3M6OmdlbW06OkdlbW1Vbml2ZXJzYWxNb2RlOjprR3JvdXBlZCwKICAgICAgICB7Z3JvdXBzLCBwcm9ibGVtX3NpemVzX2RldmljZS5nZXQoKSwgcHJvYmxlbV9zaXplc19ob3N0LmRhdGEoKX0sCiAgICAgICAge3B0cl9BLmdldCgpLCBzdHJpZGVfQS5nZXQoKSwgcHRyX0IuZ2V0KCksIHN0cmlkZV9CLmdldCgpLAogICAgICAgICBwdHJfU0ZBLmdldCgpLCBsYXlvdXRfU0ZBLmdldCgpLCBwdHJfU0ZCLmdldCgpLCBsYXlvdXRfU0ZCLmdldCgpfSwKICAgICAgICB7ZnVzaW9uX2FyZ3MsIHB0cl9DLmdldCgpLCBzdHJpZGVfQy5nZXQoKSwgcHRyX0QuZ2V0KCksIHN0cmlkZV9ELmdldCgpfSwKICAgICAgICBod19pbmZvLCBzY2hlZHVsZXIKICAgICAgfTsKCiAgICAgIEdlbW0gZ2VtbTsKICAgICAgc2l6ZV90IHdvcmtzcGFjZV9zaXplID0gR2VtbTo6Z2V0X3dvcmtzcGFjZV9zaXplKGFyZ3VtZW50cyk7CiAgICAgIGlmICghd29ya3NwYWNlX3RlbnNvci5kZWZpbmVkKCkgfHwgY2FjaGVkX2RldmljZSAhPSBkZXZpY2VfaWQgfHwgd29ya3NwYWNlX3NpemVfY2FjaGVkIDwgd29ya3NwYWNlX3NpemUpIHsKICAgICAgICBhdXRvIG9wdHMgPSB0b3JjaDo6VGVuc29yT3B0aW9ucygpLmRldmljZSh0b3JjaDo6a0NVREEsIGRldmljZV9pZCkuZHR5cGUodG9yY2g6OmtVSW50OCk7CiAgICAgICAgd29ya3NwYWNlX3RlbnNvciA9IHRvcmNoOjplbXB0eSh7c3RhdGljX2Nhc3Q8bG9uZz4od29ya3NwYWNlX3NpemUpfSwgb3B0cyk7CiAgICAgICAgd29ya3NwYWNlX3NpemVfY2FjaGVkID0gd29ya3NwYWNlX3NpemU7CiAgICAgIH0KICAgICAgdm9pZCogd29ya3NwYWNlX3B0ciA9IHdvcmtzcGFjZV9zaXplID8gd29ya3NwYWNlX3RlbnNvci5kYXRhX3B0cigpIDogbnVsbHB0cjsKCiAgICAgIENVVExBU1NfQ0hFQ0soZ2VtbS5jYW5faW1wbGVtZW50KGFyZ3VtZW50cykpOwogICAgICBDVVRMQVNTX0NIRUNLKGdlbW0uaW5pdGlhbGl6ZShhcmd1bWVudHMsIHdvcmtzcGFjZV9wdHIsIHN0cmVhbSkpOwogICAgICBhdXRvIHJ1bl9zdGF0dXMgPSBnZW1tLnJ1bihzdHJlYW0sIG51bGxwdHIsIHRydWUpOwogICAgICBpZiAocnVuX3N0YXR1cyAhPSBjdXRsYXNzOjpTdGF0dXM6OmtTdWNjZXNzKSB7CiAgICAgICAgcnVuX3N0YXR1cyA9IGdlbW0ucnVuKHN0cmVhbSk7CiAgICAgIH0KICAgICAgQ1VUTEFTU19DSEVDSyhydW5fc3RhdHVzKTsKCiAgICAgIHJldHVybiBDOwogICAgfQoKICAgIHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+IGdyb3VwZWRfZ2VtbV8xc20oCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIEEsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIEIsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIEMsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIFNGQSwKICAgICAgICBjb25zdCBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiYgU0ZCKSB7CiAgICAgIHJldHVybiBydW5fZ3JvdXBlZF9pbXBsPEdlbW0xU00+KEEsIEIsIEMsIFNGQSwgU0ZCKTsKICAgIH0KCiAgICBzdGQ6OnZlY3Rvcjx0b3JjaDo6VGVuc29yPiBncm91cGVkX2dlbW1fMnNtKAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBBLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBCLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBDLAogICAgICAgIGNvbnN0IHN0ZDo6dmVjdG9yPHRvcmNoOjpUZW5zb3I+JiBTRkEsCiAgICAgICAgY29uc3Qgc3RkOjp2ZWN0b3I8dG9yY2g6OlRlbnNvcj4mIFNGQikgewogICAgICByZXR1cm4gcnVuX2dyb3VwZWRfaW1wbDxHZW1tMlNNPihBLCBCLCBDLCBTRkEsIFNGQik7CiAgICB9CiAgICAK"_ext_mod = None_ext_fail = False⋯ 125 unchanged linescpp_src = _dec(_CPP_B64)cu_src = _dec(_CU_B64)_ext_mod = load_inline(- name="nvfp4_grouped_cutlass_ext",+ name="nvfp4_grouped_cutlass_ext_m128",cpp_sources=cpp_src,cuda_sources=cu_src,functions=["grouped_gemm_1sm", "grouped_gemm_2sm"],⋯ 40 unchanged linesitems.append((a2, b2, c2, sfa_reordered, sfb_reordered, m, k))def _use_2sm(m: int, k: int) -> bool:- return m >= 256 and k >= 4096+ return m >= 128 and k >= 2048def _gather(src):return (
scrolls · 27 diff lines total
Best evidence level for this revision: reported
JSON