+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- id="svg4986"
- version="1.1"
- inkscape:version="0.91 r13725"
- xml:space="preserve"
- width="454.94739"
- height="132.55138"
- viewBox="0 0 454.94739 132.55138"
- sodipodi:docname="Hailo_Logo_RGB.svg"><metadata
- id="metadata4992"><rdf:RDF><cc:Work
- rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
- id="defs4990"><clipPath
- clipPathUnits="userSpaceOnUse"
- id="clipPath5014"><path
- d="M 0,110 370,110 370,0 0,0 0,110 Z"
- id="path5016"
- inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1"
- objecttolerance="10"
- gridtolerance="10"
- guidetolerance="10"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:window-width="2048"
- inkscape:window-height="1100"
- id="namedview4988"
- showgrid="false"
- inkscape:zoom="2.9109866"
- inkscape:cx="216.90465"
- inkscape:cy="59.262279"
- inkscape:window-x="0"
- inkscape:window-y="0"
- inkscape:window-maximized="1"
- inkscape:current-layer="g4994"
- fit-margin-top="0"
- fit-margin-left="0"
- fit-margin-right="0"
- fit-margin-bottom="0" /><g
- id="g4994"
- inkscape:groupmode="layer"
- inkscape:label="Hailo_Logo_RGB"
- transform="matrix(1.25,0,0,-1.25,-5.127625,136.24475)"><g
- id="g4996"
- transform="translate(172.3149,50.2915)"><path
- d="M 0,0 -14.161,0 -40.557,47.98 -40.674,48.181 -40.793,47.98 -67.189,0 -81.35,0 l 34.496,58.684 -0.011,0.02 0.023,0 12.334,0 0.023,0 -0.011,-0.02 L 0,0 Z"
- style="fill:#0098c4;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path4998"
- inkscape:connector-curvature="0" /></g><path
- d="m 186.287,50.291 14.16,0 0,58.704 -14.16,0 0,-58.704 z"
- style="fill:#0098c4;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5000"
- inkscape:connector-curvature="0" /><g
- id="g5002"
- transform="translate(4.2656,50.2915)"><path
- d="m 0,0 14.298,0 0,24.747 44.268,0 0,-24.747 14.161,0 0,58.704 -14.161,0 0,-22.272 -44.268,0 0,22.272 L 0,58.704 0,0 Z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5004"
- inkscape:connector-curvature="0" /></g><g
- id="g5006"
- transform="translate(221.0957,50.2915)"><path
- d="m 0,0 59.941,0 0,10.999 -45.643,0 0,47.705 L 0,58.704 0,0 Z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5008"
- inkscape:connector-curvature="0" /></g><g
- id="g5010"><g
- id="g5012"
- clip-path="url(#clipPath5014)"><g
- id="g5018"
- transform="translate(368.06,64.1768)"><path
- d="m 0,0 0,30.933 c 0,11.274 -3.712,13.886 -15.123,13.886 l -44.956,0 c -11.411,0 -15.123,-2.612 -15.123,-13.886 l 0,-30.933 c 0,-11.136 3.575,-13.885 15.123,-13.885 l 44.956,0 C -3.712,-13.885 0,-11.136 0,0 m -14.16,-2.612 -46.881,0 0,36.569 46.881,0 0,-36.569 z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5020"
- inkscape:connector-curvature="0" /></g><g
- id="g5022"
- transform="translate(15.4511,10.2974)"><path
- d="m 0,0 0.106,-1.816 c -1.637,-0.106 -4.272,-0.16 -7.903,-0.16 -1.086,0 -1.945,0.289 -2.577,0.868 -0.632,0.578 -0.957,1.357 -0.975,2.337 l 0,12.068 c 0.018,0.979 0.343,1.758 0.975,2.337 0.632,0.578 1.491,0.867 2.577,0.867 3.631,0 6.266,-0.053 7.903,-0.16 L 0,14.499 l -7.396,0 c -1.069,0 -1.603,-0.587 -1.603,-1.762 l 0,-4.006 7.957,0 0,-1.896 -7.957,0 0,-5.046 C -8.999,0.596 -8.465,0 -7.396,0 L 0,0 Z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5024"
- inkscape:connector-curvature="0" /></g><g
- id="g5026"
- transform="translate(23.7817,21.3521)"><path
- d="m 0,0 0.134,-2.056 c 1.833,1.584 3.604,2.376 5.313,2.376 1.816,0 2.911,-0.765 3.284,-2.296 1.763,1.531 3.507,2.296 5.234,2.296 1.121,0 1.98,-0.303 2.577,-0.907 0.596,-0.606 0.895,-1.496 0.895,-2.671 l 0,-9.746 -2.244,0 0,9.106 c -0.018,0.8 -0.182,1.383 -0.494,1.748 -0.311,0.365 -0.823,0.547 -1.535,0.547 -0.623,0 -1.224,-0.142 -1.802,-0.426 -0.579,-0.285 -1.402,-0.82 -2.47,-1.603 l 0,-9.372 -2.19,0 0,9.106 c 0,0.818 -0.164,1.405 -0.494,1.762 C 5.879,-1.78 5.367,-1.603 4.673,-1.603 4.05,-1.603 3.449,-1.745 2.871,-2.029 2.292,-2.314 1.469,-2.84 0.401,-3.605 l 0,-9.399 -2.27,0 L -1.869,0 0,0 Z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5028"
- inkscape:connector-curvature="0" /></g><g
- id="g5030"
- transform="translate(50.1899,17.6938)"><path
- d="m 0,0 0,-6.889 c 1.815,-0.534 3.204,-0.801 4.166,-0.801 1.174,0 1.993,0.329 2.456,0.988 0.462,0.658 0.694,1.922 0.694,3.791 0,1.816 -0.218,3.089 -0.654,3.819 C 6.226,1.637 5.482,2.002 4.432,2.002 3.755,2.002 3.084,1.847 2.417,1.535 1.749,1.224 0.943,0.711 0,0 m -0.401,3.658 0.187,-2.083 c 0.694,0.748 1.531,1.335 2.51,1.762 0.979,0.428 1.94,0.642 2.884,0.642 1.549,0 2.679,-0.57 3.391,-1.709 0.712,-1.14 1.068,-2.867 1.068,-5.181 0,-2.456 -0.391,-4.196 -1.175,-5.22 -0.783,-1.024 -2.029,-1.535 -3.738,-1.535 -1.709,0 -3.311,0.445 -4.806,1.335 C -0.027,-8.937 0,-9.809 0,-10.948 l 0,-3.765 -2.27,0 0,18.371 1.869,0 z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5032"
- inkscape:connector-curvature="0" /></g><g
- id="g5034"
- transform="translate(74.581,18.7085)"><path
- d="m 0,0 c -0.543,0.694 -1.526,1.041 -2.95,1.041 -1.425,0 -2.404,-0.347 -2.938,-1.041 -0.534,-0.694 -0.8,-1.985 -0.8,-3.872 0,-1.887 0.266,-3.177 0.8,-3.872 0.534,-0.694 1.513,-1.041 2.938,-1.041 1.424,0 2.407,0.347 2.95,1.041 0.543,0.695 0.814,1.985 0.814,3.872 C 0.814,-1.985 0.543,-0.694 0,0 m -2.95,2.964 c 2.242,0 3.822,-0.517 4.739,-1.549 0.917,-1.033 1.375,-2.795 1.375,-5.287 0,-2.492 -0.458,-4.254 -1.375,-5.287 -0.917,-1.032 -2.497,-1.549 -4.739,-1.549 -2.226,0 -3.801,0.517 -4.727,1.549 -0.926,1.033 -1.388,2.795 -1.388,5.287 0,2.492 0.462,4.254 1.388,5.287 0.926,1.032 2.501,1.549 4.727,1.549"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5036"
- inkscape:connector-curvature="0" /></g><g
- id="g5038"
- transform="translate(103.165,21.3521)"><path
- d="m 0,0 -3.792,-12.363 c -0.106,-0.428 -0.4,-0.641 -0.881,-0.641 l -2.056,0 c -0.213,0 -0.405,0.067 -0.574,0.2 -0.169,0.134 -0.271,0.307 -0.307,0.521 l -2.136,8.838 c -0.053,0.249 -0.125,0.601 -0.213,1.055 -0.09,0.454 -0.161,0.787 -0.214,1.001 l -0.321,0 -0.454,-2.056 -2.109,-8.838 c -0.125,-0.481 -0.427,-0.721 -0.908,-0.721 l -2.029,0 c -0.481,0 -0.775,0.213 -0.881,0.641 L -20.667,0 l 2.35,0 2.697,-9.586 c 0.16,-0.552 0.302,-1.202 0.427,-1.949 l 0.347,0 0.481,1.949 2.162,8.865 c 0.089,0.48 0.374,0.721 0.855,0.721 l 2.056,0 c 0.445,0 0.729,-0.25 0.854,-0.748 l 2.137,-8.838 c 0.035,-0.196 0.106,-0.512 0.213,-0.948 0.107,-0.436 0.187,-0.77 0.24,-1.001 l 0.348,0 c 0.017,0.089 0.075,0.369 0.173,0.841 0.098,0.471 0.191,0.841 0.281,1.108 L -2.35,0 0,0 Z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5040"
- inkscape:connector-curvature="0" /></g><g
- id="g5042"
- transform="translate(110.2675,15.5044)"><path
- d="M 0,0 5.5,0 C 6.444,0 6.916,0.641 6.916,1.922 6.898,2.759 6.649,3.355 6.168,3.711 5.687,4.067 4.869,4.245 3.711,4.245 2.34,4.245 1.389,3.947 0.854,3.351 0.32,2.754 0.036,1.637 0,0 m 6.088,-1.763 -6.061,0 c 0.124,-1.495 0.489,-2.501 1.095,-3.017 0.605,-0.516 1.61,-0.774 3.017,-0.774 1.477,0 2.981,0.107 4.512,0.32 l 0.241,-1.522 c -1.158,-0.48 -2.84,-0.721 -5.047,-0.721 -2.243,0 -3.841,0.521 -4.793,1.562 -0.952,1.042 -1.428,2.808 -1.428,5.301 0,2.51 0.462,4.267 1.388,5.273 0.926,1.006 2.457,1.509 4.592,1.509 C 5.545,6.168 6.96,5.816 7.85,5.113 8.74,4.41 9.186,3.346 9.186,1.922 9.221,-0.534 8.188,-1.763 6.088,-1.763"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5044"
- inkscape:connector-curvature="0" /></g><g
- id="g5046"
- transform="translate(133.9511,21.6724)"><path
- d="m 0,0 -0.267,-2.136 -0.748,0 c -0.658,0 -1.339,-0.13 -2.042,-0.387 -0.704,-0.259 -1.642,-0.681 -2.817,-1.269 l 0,-9.532 -2.27,0 0,13.004 1.763,0 0.24,-2.056 C -4.13,-0.792 -2.279,0 -0.587,0 L 0,0 Z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5048"
- inkscape:connector-curvature="0" /></g><path
- d="m 141.801,8.348 -2.243,0 0,13.004 2.243,0 0,-13.004 z m -1.656,18.531 1.069,0 c 0.462,0 0.694,-0.232 0.694,-0.694 l 0,-1.522 c 0,-0.463 -0.232,-0.694 -0.694,-0.694 l -1.069,0 c -0.462,0 -0.694,0.231 -0.694,0.694 l 0,1.522 c 0,0.462 0.232,0.694 0.694,0.694"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5050"
- inkscape:connector-curvature="0" /><g
- id="g5052"
- transform="translate(150.6127,21.3521)"><path
- d="m 0,0 0.16,-2.056 c 2.1,1.584 4.041,2.376 5.821,2.376 2.35,0 3.525,-1.193 3.525,-3.578 l 0,-9.746 -2.27,0 0,9.106 c 0,0.854 -0.143,1.45 -0.427,1.788 -0.285,0.339 -0.766,0.507 -1.442,0.507 -0.712,0 -1.429,-0.16 -2.15,-0.48 -0.72,-0.32 -1.677,-0.846 -2.87,-1.575 l 0,-9.346 -2.27,0 L -1.923,0 0,0 Z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5054"
- inkscape:connector-curvature="0" /></g><g
- id="g5056"
- transform="translate(169.25,15.6777)"><path
- d="m 0,0 c 0.516,-0.365 1.415,-0.547 2.697,-0.547 1.282,0 2.18,0.182 2.697,0.547 0.516,0.365 0.774,0.983 0.774,1.856 0,0.872 -0.254,1.491 -0.761,1.855 C 4.899,4.076 3.996,4.259 2.697,4.259 1.415,4.259 0.516,4.076 0,3.711 -0.517,3.347 -0.774,2.728 -0.774,1.856 -0.774,0.983 -0.517,0.365 0,0 M 4.593,-6.715 0.16,-6.101 c -0.908,-0.694 -1.362,-1.523 -1.362,-2.483 0,-0.908 0.267,-1.504 0.801,-1.79 0.534,-0.284 1.611,-0.427 3.231,-0.427 1.585,0 2.648,0.147 3.191,0.441 0.543,0.294 0.814,0.885 0.814,1.776 0,0.64 -0.138,1.077 -0.413,1.308 -0.276,0.231 -0.886,0.418 -1.829,0.561 M 9.666,4.419 7.743,4.259 C 8.099,3.671 8.277,2.871 8.277,1.856 8.277,0.396 7.859,-0.659 7.022,-1.309 6.186,-1.958 4.744,-2.283 2.697,-2.283 1.7,-2.283 0.801,-2.194 0,-2.016 c -0.338,-0.41 -0.437,-0.859 -0.294,-1.348 0.143,-0.49 0.543,-0.788 1.202,-0.895 l 4.86,-0.774 c 1.21,-0.178 2.06,-0.557 2.549,-1.135 0.49,-0.579 0.735,-1.419 0.735,-2.523 0,-1.513 -0.45,-2.564 -1.349,-3.151 -0.899,-0.588 -2.514,-0.881 -4.846,-0.881 -2.35,0 -3.983,0.289 -4.9,0.868 -0.917,0.578 -1.375,1.606 -1.375,3.084 0,0.765 0.16,1.379 0.48,1.842 0.321,0.463 0.864,0.899 1.629,1.308 -0.658,0.517 -0.961,1.202 -0.907,2.057 0.053,0.854 0.391,1.522 1.014,2.002 -1.104,0.587 -1.655,1.718 -1.655,3.391 0,1.495 0.414,2.564 1.241,3.204 0.828,0.641 2.274,0.962 4.34,0.962 1.228,0 2.233,-0.107 3.017,-0.321 l 4.058,0 -0.133,-1.255 z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5058"
- inkscape:connector-curvature="0" /></g><path
- d="m 201.456,8.348 -2.35,0 0,18.424 2.35,0 0,-18.424 z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5060"
- inkscape:connector-curvature="0" /><g
- id="g5062"
- transform="translate(210.4013,21.3521)"><path
- d="m 0,0 0.16,-2.056 c 2.1,1.584 4.041,2.376 5.821,2.376 2.35,0 3.525,-1.193 3.525,-3.578 l 0,-9.746 -2.27,0 0,9.106 c 0,0.854 -0.143,1.45 -0.427,1.788 -0.285,0.339 -0.766,0.507 -1.442,0.507 -0.712,0 -1.429,-0.16 -2.15,-0.48 -0.72,-0.32 -1.677,-0.846 -2.87,-1.575 l 0,-9.346 -2.27,0 L -1.923,0 0,0 Z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5064"
- inkscape:connector-curvature="0" /></g><g
- id="g5066"
- transform="translate(230.08,19.563)"><path
- d="M 0,0 0,-7.637 C 0,-8.26 0.133,-8.705 0.4,-8.972 0.667,-9.239 1.122,-9.373 1.762,-9.373 l 1.976,0 0.267,-1.735 c -0.819,-0.231 -1.798,-0.347 -2.937,-0.347 -1.086,0 -1.914,0.302 -2.483,0.908 -0.57,0.605 -0.855,1.477 -0.855,2.616 l 0,7.931 -2.35,0 0,1.655 2.35,0.107 0,3.872 2.27,0 0,-3.845 4.139,0 L 4.139,0 0,0 Z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5068"
- inkscape:connector-curvature="0" /></g><g
- id="g5070"
- transform="translate(241.455,15.5044)"><path
- d="M 0,0 5.5,0 C 6.444,0 6.916,0.641 6.916,1.922 6.898,2.759 6.649,3.355 6.168,3.711 5.687,4.067 4.869,4.245 3.711,4.245 2.34,4.245 1.389,3.947 0.854,3.351 0.32,2.754 0.036,1.637 0,0 m 6.088,-1.763 -6.061,0 c 0.124,-1.495 0.489,-2.501 1.095,-3.017 0.605,-0.516 1.61,-0.774 3.017,-0.774 1.477,0 2.981,0.107 4.512,0.32 l 0.241,-1.522 c -1.158,-0.48 -2.84,-0.721 -5.047,-0.721 -2.243,0 -3.841,0.521 -4.793,1.562 -0.952,1.042 -1.428,2.808 -1.428,5.301 0,2.51 0.462,4.267 1.388,5.273 0.926,1.006 2.457,1.509 4.592,1.509 C 5.545,6.168 6.96,5.816 7.85,5.113 8.74,4.41 9.186,3.346 9.186,1.922 9.221,-0.534 8.188,-1.763 6.088,-1.763"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5072"
- inkscape:connector-curvature="0" /></g><g
- id="g5074"
- transform="translate(259.0776,27.0391)"><path
- d="m 0,0 0,-15.113 c -0.018,-0.57 0.125,-1.001 0.427,-1.295 0.303,-0.294 0.748,-0.441 1.336,-0.441 l 1.255,0 0.267,-1.735 c -0.481,-0.231 -1.273,-0.347 -2.377,-0.347 -0.979,0 -1.754,0.289 -2.323,0.868 -0.57,0.578 -0.855,1.392 -0.855,2.443 L -2.27,0 0,0 Z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5076"
- inkscape:connector-curvature="0" /></g><g
- id="g5078"
- transform="translate(269.7314,27.0391)"><path
- d="m 0,0 0,-15.113 c -0.018,-0.57 0.125,-1.001 0.427,-1.295 0.303,-0.294 0.748,-0.441 1.336,-0.441 l 1.255,0 0.267,-1.735 c -0.481,-0.231 -1.273,-0.347 -2.377,-0.347 -0.979,0 -1.754,0.289 -2.323,0.868 -0.57,0.578 -0.855,1.392 -0.855,2.443 L -2.27,0 0,0 Z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5080"
- inkscape:connector-curvature="0" /></g><path
- d="m 280.546,8.348 -2.243,0 0,13.004 2.243,0 0,-13.004 z m -1.656,18.531 1.068,0 c 0.463,0 0.694,-0.232 0.694,-0.694 l 0,-1.522 c 0,-0.463 -0.231,-0.694 -0.694,-0.694 l -1.068,0 c -0.463,0 -0.694,0.231 -0.694,0.694 l 0,1.522 c 0,0.462 0.231,0.694 0.694,0.694"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5082"
- inkscape:connector-curvature="0" /><g
- id="g5084"
- transform="translate(289.8642,15.6777)"><path
- d="m 0,0 c 0.516,-0.365 1.415,-0.547 2.697,-0.547 1.282,0 2.18,0.182 2.697,0.547 0.516,0.365 0.774,0.983 0.774,1.856 0,0.872 -0.254,1.491 -0.761,1.855 C 4.899,4.076 3.996,4.259 2.697,4.259 1.415,4.259 0.516,4.076 0,3.711 -0.517,3.347 -0.774,2.728 -0.774,1.856 -0.774,0.983 -0.517,0.365 0,0 M 4.593,-6.715 0.16,-6.101 c -0.908,-0.694 -1.362,-1.523 -1.362,-2.483 0,-0.908 0.267,-1.504 0.801,-1.79 0.534,-0.284 1.611,-0.427 3.231,-0.427 1.585,0 2.648,0.147 3.191,0.441 0.543,0.294 0.814,0.885 0.814,1.776 0,0.64 -0.138,1.077 -0.413,1.308 -0.276,0.231 -0.886,0.418 -1.829,0.561 M 9.666,4.419 7.743,4.259 C 8.099,3.671 8.277,2.871 8.277,1.856 8.277,0.396 7.859,-0.659 7.022,-1.309 6.186,-1.958 4.744,-2.283 2.697,-2.283 1.7,-2.283 0.801,-2.194 0,-2.016 c -0.338,-0.41 -0.437,-0.859 -0.294,-1.348 0.143,-0.49 0.543,-0.788 1.202,-0.895 l 4.86,-0.774 c 1.21,-0.178 2.06,-0.557 2.549,-1.135 0.49,-0.579 0.735,-1.419 0.735,-2.523 0,-1.513 -0.45,-2.564 -1.349,-3.151 -0.899,-0.588 -2.514,-0.881 -4.846,-0.881 -2.35,0 -3.983,0.289 -4.9,0.868 -0.917,0.578 -1.375,1.606 -1.375,3.084 0,0.765 0.16,1.379 0.48,1.842 0.321,0.463 0.864,0.899 1.629,1.308 -0.658,0.517 -0.961,1.202 -0.907,2.057 0.053,0.854 0.391,1.522 1.014,2.002 -1.104,0.587 -1.655,1.718 -1.655,3.391 0,1.495 0.414,2.564 1.241,3.204 0.828,0.641 2.274,0.962 4.34,0.962 1.228,0 2.233,-0.107 3.017,-0.321 l 4.058,0 -0.133,-1.255 z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5086"
- inkscape:connector-curvature="0" /></g><g
- id="g5088"
- transform="translate(306.7929,15.5044)"><path
- d="M 0,0 5.5,0 C 6.444,0 6.916,0.641 6.916,1.922 6.898,2.759 6.649,3.355 6.168,3.711 5.687,4.067 4.869,4.245 3.711,4.245 2.34,4.245 1.389,3.947 0.854,3.351 0.32,2.754 0.036,1.637 0,0 m 6.088,-1.763 -6.061,0 c 0.124,-1.495 0.489,-2.501 1.095,-3.017 0.605,-0.516 1.61,-0.774 3.017,-0.774 1.477,0 2.981,0.107 4.512,0.32 l 0.241,-1.522 c -1.158,-0.48 -2.84,-0.721 -5.047,-0.721 -2.243,0 -3.841,0.521 -4.793,1.562 -0.952,1.042 -1.428,2.808 -1.428,5.301 0,2.51 0.462,4.267 1.388,5.273 0.926,1.006 2.457,1.509 4.592,1.509 C 5.545,6.168 6.96,5.816 7.85,5.113 8.74,4.41 9.186,3.346 9.186,1.922 9.221,-0.534 8.188,-1.763 6.088,-1.763"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5090"
- inkscape:connector-curvature="0" /></g><g
- id="g5092"
- transform="translate(323.935,21.3521)"><path
- d="m 0,0 0.16,-2.056 c 2.1,1.584 4.041,2.376 5.821,2.376 2.35,0 3.525,-1.193 3.525,-3.578 l 0,-9.746 -2.27,0 0,9.106 c 0,0.854 -0.143,1.45 -0.427,1.788 -0.285,0.339 -0.766,0.507 -1.442,0.507 -0.712,0 -1.429,-0.16 -2.15,-0.48 -0.72,-0.32 -1.677,-0.846 -2.87,-1.575 l 0,-9.346 -2.27,0 L -1.923,0 0,0 Z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5094"
- inkscape:connector-curvature="0" /></g><g
- id="g5096"
- transform="translate(349.7817,10.2173)"><path
- d="m 0,0 0.241,-1.522 c -1.282,-0.445 -2.769,-0.667 -4.46,-0.667 -2.242,0 -3.831,0.511 -4.766,1.535 -0.934,1.023 -1.402,2.79 -1.402,5.3 0,2.51 0.468,4.272 1.402,5.287 0.935,1.015 2.532,1.522 4.793,1.522 1.709,0 3.106,-0.205 4.192,-0.614 L -0.293,9.372 c -1.175,0.107 -2.35,0.16 -3.525,0.16 -1.567,0 -2.653,-0.346 -3.258,-1.041 -0.605,-0.694 -0.907,-1.976 -0.907,-3.845 0,-1.887 0.302,-3.177 0.907,-3.872 0.605,-0.694 1.691,-1.041 3.258,-1.041 1.424,0 2.697,0.089 3.818,0.267"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5098"
- inkscape:connector-curvature="0" /></g><g
- id="g5100"
- transform="translate(357.125,15.5044)"><path
- d="M 0,0 5.5,0 C 6.444,0 6.916,0.641 6.916,1.922 6.898,2.759 6.649,3.355 6.168,3.711 5.687,4.067 4.869,4.245 3.711,4.245 2.34,4.245 1.389,3.947 0.854,3.351 0.32,2.754 0.036,1.637 0,0 m 6.088,-1.763 -6.061,0 c 0.124,-1.495 0.489,-2.501 1.095,-3.017 0.605,-0.516 1.61,-0.774 3.017,-0.774 1.477,0 2.981,0.107 4.512,0.32 l 0.241,-1.522 c -1.158,-0.48 -2.84,-0.721 -5.047,-0.721 -2.243,0 -3.841,0.521 -4.793,1.562 -0.952,1.042 -1.428,2.808 -1.428,5.301 0,2.51 0.462,4.267 1.388,5.273 0.926,1.006 2.457,1.509 4.592,1.509 C 5.545,6.168 6.96,5.816 7.85,5.113 8.74,4.41 9.186,3.346 9.186,1.922 9.221,-0.534 8.188,-1.763 6.088,-1.763"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path5102"
- inkscape:connector-curvature="0" /></g></g></g></g></svg>
\ No newline at end of file
cmake_minimum_required(VERSION 3.0.0)
option(HAILO_BUILD_PYBIND "Build Python binding" OFF)
-option(HAILO_BUILD_PYHAILORT_VENV "Build pyhailort in venv" ON)
+option(HAILO_BUILD_PYHAILORT_VENV "Build pyhailort in venv. Only used if HAILO_BUILD_PYBIND is on" ON)
option(HAILO_BUILD_EMULATOR "Build hailort for emulator" OFF)
option(HAILO_BUILD_UT "Build Unit Tests" OFF)
option(HAILO_BUILD_GSTREAMER "Compile gstreamer plugins" OFF)
option(HAILO_BUILD_EXAMPLES "Build examples" OFF)
+option(HAILO_OFFLINE_COMPILATION "Don't download external dependencies" OFF)
+option(HAILO_MICROPROFILE "Microprofile code" OFF)
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
project(HailoRT)
+# Prevent in-tree building
+if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
+ message(FATAL_ERROR "In-source builds are not allowed.
+ Please remove the `CMakeCache.txt` file and `CMakeFiles` directory from `${CMAKE_SOURCE_DIR}`
+ In order to build, please create a new `build` directory and run `cmake ..` from there.")
+endif()
+
# Check build type
if (NOT CMAKE_BUILD_TYPE)
message(STATUS "No build type selected, default to Debug")
/wd4251 # C++ ABI with STL
)
add_definitions(-D_CRT_SECURE_NO_WARNINGS) # Disable "unsafe function" warnings
-
- if (CMAKE_BUILD_TYPE STREQUAL "Release")
- set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} /O2 /DNDEBUG /Zi)
- elseif(CMAKE_BUILD_TYPE STREQUAL "Debug")
- set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} /Od /Zi /DDEBUG)
- else()
- message(FATAL_ERROR "Invalid value for CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
- endif()
- add_link_options("$<$<NOT:$<CONFIG:Debug>>:/DEBUG>")
- add_link_options("$<$<NOT:$<CONFIG:Debug>>:/OPT:REF>")
- add_link_options("$<$<NOT:$<CONFIG:Debug>>:/OPT:ICF>")
-
elseif(UNIX)
- if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "QCC")
set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} -Werror -Wall -Wextra -Wconversion)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
- set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} -Werror -Wall -Wextra
+ set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} -Werror -Wall -Wextra
# TODO: remove me warnings
-Wno-conversion
-Wno-deprecated-declarations
else()
message(FATAL_ERROR "Invalid value for CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}")
endif()
-
- if (CMAKE_BUILD_TYPE STREQUAL "Release")
- set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} -O3 -DNDEBUG)
- elseif(CMAKE_BUILD_TYPE STREQUAL "Debug")
- set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} -O0 -g -DDEBUG)
- else()
- message(FATAL_ERROR "Invalid value for CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
- endif()
else()
message(FATAL_ERROR "Unexpeced host, stopping build")
endif()
set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} -DHAILO_EMULATOR)
endif()
-# Prevent in-tree building
-if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
- message(FATAL_ERROR "In-source builds are not allowed.
- Please remove the `CMakeCache.txt` file and `CMakeFiles` directory from `${CMAKE_SOURCE_DIR}`
- In order to build, please create a new `build` directory and run `cmake ..` from there.")
-endif()
-
# Enable output of compile commands during generation
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
-# Set validation dir
-set(PLATFORM_VALIDATION_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/platform_internals/hailo_platform_internals/validation")
-
-if (NOT DEFINED HEFS_DIR)
- set(HEFS_DIR "${PLATFORM_VALIDATION_DIRECTORY}/hefs/latest")
- message(STATUS "No HEFS_DIR provided, using default ('${HEFS_DIR}')")
-endif()
-
# Add subdirectories
add_subdirectory(hailort)
<p align="left">
- <img src=".logo.svg" />
+ <img src=".hailort.png" />
</p>
#define CONTEXT_SWITCH_DEFS__TIMESTAMP_INIT_VALUE (0xFFFFFFFF)
#define CONTEXT_SWITCH_DEFS__ENABLE_LCU_DEFAULT_KERNEL_ADDRESS (1)
#define CONTEXT_SWITCH_DEFS__ENABLE_LCU_DEFAULT_KERNEL_COUNT (2)
-#define CONTEXT_SWITCH_DEFS__ENABLE_LCU_DEFAULT_BATCH_SIZE (1)
#define CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_LCU_INDEX_SHIFT (0)
#define CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_LCU_INDEX_WIDTH (4)
#else
typedef enum __attribute__((packed)) {
#endif
- CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_VDMA_DESCRIPTORS = 0,
+ CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_CFG_CHANNEL_DESCRIPTORS = 0,
CONTEXT_SWITCH_DEFS__ACTION_TYPE_TRIGGER_SEQUENCER,
CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_DATA_FROM_VDMA_CHANNEL,
CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_LCU_DEFAULT,
CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_DMA_IDLE_ACTION,
CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_NMS_IDLE,
CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_CCW_BURSTS,
+ CONTEXT_SWITCH_DEFS__ACTION_TYPE_VALIDATE_VDMA_CHANNEL,
+ CONTEXT_SWITCH_DEFS__ACTION_TYPE_BURST_CREDITS_TASK_START,
/* Must be last */
CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT
* | | | .last_executed = <last_action_executed_in_repeated>; |
* | | | .sub_action_type = CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_LCU_DEFAULT; |
* | | | } |
- * | | | CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t { .packed_lcu_id=<some_lcu_id>; } |
- * | | | CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t { .packed_lcu_id=<some_lcu_id>; } |
- * | V | CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t { .packed_lcu_id=<some_lcu_id>; } |
+ * | | | CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t { |
+ * | | | .packed_lcu_id=<some_lcu_id>; |
+ * | | | .network_index=<some_network_index> |
+ * | | | } |
+ * | | | CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t { |
+ * | | | .packed_lcu_id=<some_lcu_id>; |
+ * | | | .network_index=<some_network_index> |
+ * | | | } |
+ * | | | CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t { |
+ * | | | .packed_lcu_id=<some_lcu_id>; |
+ * | | | .network_index=<some_network_index> |
+ * | V | } |
* | ... | (Next action starting with CONTEXT_SWITCH_DEFS__common_action_header_t) |
* |-------------------------------------------------------------------------------------------------------|
* See also: "CONTROL_PROTOCOL__REPEATED_ACTION_t" in "control_protocol.h"
typedef struct {
uint16_t descriptors_count;
uint8_t cfg_channel_number;
-} CONTEXT_SWITCH_DEFS__read_vdma_action_data_t;
+} CONTEXT_SWITCH_DEFS__fetch_cfg_channel_descriptors_action_data_t;
typedef struct {
uint16_t ccw_bursts;
typedef struct {
uint8_t packed_lcu_id;
+ uint8_t network_index;
uint16_t kernel_done_address;
uint32_t kernel_done_count;
} CONTEXT_SWITCH_DEFS__enable_lcu_action_non_default_data_t;
/* Default action - kernel_done_address and kernel_done_count has default values */
typedef struct {
uint8_t packed_lcu_id;
+ uint8_t network_index;
} CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t;
typedef struct {
uint8_t vdma_channel_index;
uint8_t edge_layer_direction;
bool is_inter_context;
+ uint8_t host_buffer_type; // CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t
+ uint32_t initial_credit_size;
} CONTEXT_SWITCH_DEFS__deactivate_vdma_channel_action_data_t;
+typedef struct {
+ uint8_t vdma_channel_index;
+ uint8_t edge_layer_direction;
+ bool is_inter_context;
+ bool is_single_context_network_group;
+ uint8_t host_buffer_type; // CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t
+ uint32_t initial_credit_size;
+} CONTEXT_SWITCH_DEFS__validate_vdma_channel_action_data_t;
+
typedef struct {
uint8_t vdma_channel_index;
uint8_t stream_index;
- uint32_t channel_credits;
+ uint8_t network_index;
+ uint32_t frame_periph_size;
uint8_t credit_type;
uint16_t periph_bytes_per_buffer;
+ uint8_t host_buffer_type; // CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t, relevant only for descriptors credit.
} CONTEXT_SWITCH_DEFS__fetch_data_action_data_t;
typedef struct {
typedef struct {
uint8_t h2d_vdma_channel_index;
uint8_t d2h_vdma_channel_index;
- uint32_t descriptors_per_batch;
+ uint8_t network_index;
+ uint32_t descriptors_per_frame;
uint16_t programmed_descriptors_count;
} CONTEXT_SWITCH_DEFS__add_ddr_pair_info_action_data_t;
uint8_t stream_index;
uint8_t vdma_channel_index;
CONTEXT_SWITCH_DEFS__stream_reg_info_t stream_reg_info;
+ uint32_t initial_credit_size;
bool is_single_context_app;
} CONTEXT_SWITCH_DEFS__activate_boundary_input_data_t;
typedef struct {
uint8_t stream_index;
uint8_t vdma_channel_index;
+ uint8_t network_index;
CONTEXT_SWITCH_DEFS__stream_reg_info_t stream_reg_info;
- uint64_t host_descriptors_base_address;
- uint16_t initial_host_available_descriptors;
- uint8_t desc_list_depth;
+ CONTROL_PROTOCOL__host_buffer_info_t host_buffer_info;
+ uint32_t initial_credit_size;
} CONTEXT_SWITCH_DEFS__activate_inter_context_input_data_t;
typedef struct {
uint8_t vdma_channel_index;
CONTEXT_SWITCH_DEFS__stream_reg_info_t stream_reg_info;
uint64_t host_descriptors_base_address;
- uint16_t initial_host_available_descriptors;
uint8_t desc_list_depth;
- bool fw_managed_channel;
+ uint32_t initial_credit_size;
} CONTEXT_SWITCH_DEFS__activate_ddr_buffer_input_data_t;
typedef struct {
typedef struct {
uint8_t stream_index;
uint8_t vdma_channel_index;
+ uint8_t network_index;
CONTEXT_SWITCH_DEFS__stream_reg_info_t stream_reg_info;
- // TODO: add this to CONTEXT_SWITCH_DEFS__stream_reg_info_t
- uint32_t frame_credits_in_bytes;
- uint64_t host_descriptors_base_address;
- uint16_t initial_host_available_descriptors;
- uint16_t desc_page_size;
- uint8_t desc_list_depth;
+ CONTROL_PROTOCOL__host_buffer_info_t host_buffer_info;
} CONTEXT_SWITCH_DEFS__activate_inter_context_output_data_t;
typedef struct {
CONTEXT_SWITCH_DEFS__stream_reg_info_t stream_reg_info;
uint32_t frame_credits_in_bytes;
uint64_t host_descriptors_base_address;
- uint16_t initial_host_available_descriptors;
uint16_t desc_page_size;
uint8_t desc_list_depth;
- bool fw_managed_channel;
+ uint32_t buffered_rows_count;
} CONTEXT_SWITCH_DEFS__activate_ddr_buffer_output_data_t;
typedef struct {
uint8_t channel_index;
- uint64_t host_descriptors_base_address;
- uint16_t initial_host_available_descriptors;
+ CONTROL_PROTOCOL__host_buffer_info_t host_buffer_info;
} CONTEXT_SWITCH_DEFS__activate_cfg_channel_t;
typedef struct {
#define CONTROL_PROTOCOL__REQUEST_BASE_SIZE (sizeof(CONTROL_PROTOCOL__request_header_t) + sizeof(uint32_t))
#define CONTROL_PROTOCOL__OPCODE_INVALID 0xFFFFFFFF
+/* If a control accepts a dynamic_batch_size and this value is passed, the
+ * dynamic_batch_size will be ignored. The pre-configured batch_size will be used.
+ */
+#define CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE (0)
+
#define CONTROL_PROTOCOL__TRIGGER_SUB_INDEX_SHIFT (0)
#define CONTROL_PROTOCOL__TRIGGER_SUB_INDEX_BIT_MASK (0x000000FF)
#define CONTROL_PROTOCOL__TRIGGER_INDEX_SHIFT (16)
CONTROL_PROTOCOL__CONTEXT_SWITCH_VER_V1_0_0 = 0x010000,
} CONTROL_PROTOCOL__CONTEXT_SWITCH_VERSION_t;
+typedef struct {
+ bool is_abbale_supported;
+} CONTROL_PROTOCOL__VALIDATION_FEATURE_LIST_t;
+
+typedef struct {
+ bool preliminary_run_asap;
+} CONTROL_PROTOCOL__INFER_FEATURE_LIST_t;
+
typedef struct {
uint8_t dynamic_contexts_count;
uint32_t host_boundary_channels_bitmap;
- uint32_t host_ddr_channels_bitmap;
- uint8_t cfg_channels_count;
uint8_t cfg_channel_numbers[CONTROL_PROTOCOL__MAX_CFG_CHANNELS];
uint8_t power_mode; // CONTROL_PROTOCOL__power_mode_t
+ CONTROL_PROTOCOL__INFER_FEATURE_LIST_t infer_features;
uint8_t networks_count;
uint16_t batch_size[CONTROL_PROTOCOL__MAX_NETWORKS_PER_NETWORK_GROUP];
} CONTROL_PROTOCOL__application_header_t;
-typedef struct {
- bool is_abbale_supported;
-} CONTROL_PROTOCOL__VALIDATION_FEATURE_LIST_t;
-
typedef struct {
uint32_t context_switch_version_length;
uint32_t context_switch_version;
CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ENABLE_LCU_DEFAULT,
CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ADD_REPEATED,
CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_FETCH_CCW_BURSTS,
+ CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_BURST_CREDITS_TASK_START,
/* must be last*/
CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_COUNT,
CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_COUNT
} CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_t;
+typedef enum {
+ CONTROL_PROTOCOL__HOST_BUFFER_TYPE_EXTERNAL_DESC = 0,
+ CONTROL_PROTOCOL__HOST_BUFFER_TYPE_CCB,
+
+ // The buffer uses external descriptors that is host managed - the firmware don't need to config this buffer
+ CONTROL_PROTOCOL__HOST_BUFFER_TYPE_HOST_MANAGED_EXTERNAL_DESC,
+
+ /* must be last*/
+ CONTROL_PROTOCOL__HOST_BUFFER_TYPE_COUNT
+} CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t;
+
+typedef struct {
+ uint8_t buffer_type; // CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t
+ uint64_t dma_address;
+ uint16_t desc_page_size;
+ uint32_t total_desc_count;
+ uint32_t bytes_in_pattern;
+} CONTROL_PROTOCOL__host_buffer_info_t;
+
typedef struct {
uint8_t communication_type;
uint8_t edge_connection_type;
typedef struct {
uint64_t host_descriptors_base_address;
- uint16_t initial_host_available_descriptors;
uint8_t desc_list_depth;
} CONTROL_PROTOCOL__host_desc_address_info_t;
typedef struct {
CONTROL_PROTOCOL__edge_layer_common_info_t common_info;
- uint32_t frame_credits_in_bytes;
- CONTROL_PROTOCOL__host_desc_address_info_t host_desc_address_info;
- uint16_t desc_page_size;
+ CONTROL_PROTOCOL__host_buffer_info_t host_buffer_info;
} CONTROL_PROTOCOL__inter_context_output_t;
typedef struct {
uint32_t frame_credits_in_bytes;
CONTROL_PROTOCOL__host_desc_address_info_t host_desc_address_info;
uint16_t desc_page_size;
- bool fw_managed_channel;
+ uint32_t buffered_rows_count;
} CONTROL_PROTOCOL__ddr_buffer_output_t;
typedef struct {
CONTROL_PROTOCOL__edge_layer_common_info_t common_info;
uint16_t desc_page_size;
+ uint32_t initial_credit_size;
} CONTROL_PROTOCOL__network_boundary_input_t;
typedef struct {
CONTROL_PROTOCOL__edge_layer_common_info_t common_info;
- CONTROL_PROTOCOL__host_desc_address_info_t host_desc_address_info;
- uint16_t desc_page_size;
- uint16_t context_credits_in_descriptors;
+ CONTROL_PROTOCOL__host_buffer_info_t host_buffer_info;
+ uint32_t initial_credit_size;
} CONTROL_PROTOCOL__inter_context_input_t;
typedef struct {
CONTROL_PROTOCOL__edge_layer_common_info_t common_info;
CONTROL_PROTOCOL__host_desc_address_info_t host_desc_address_info;
- bool fw_managed_channel;
+ uint32_t initial_credit_size;
} CONTROL_PROTOCOL__ddr_buffer_input_t;
typedef struct {
uint8_t is_first_control_per_context;
uint32_t is_last_control_per_context_length;
uint8_t is_last_control_per_context;
- uint32_t context_cfg_base_address_length;
- uint64_t context_cfg_base_address[CONTROL_PROTOCOL__MAX_CFG_CHANNELS];
- uint32_t context_cfg_total_descriptors_length;
- uint16_t context_cfg_total_descriptors[CONTROL_PROTOCOL__MAX_CFG_CHANNELS];
+ uint32_t cfg_channels_count_length;
+ uint8_t cfg_channels_count;
+ uint32_t config_buffer_infos_length;
+ CONTROL_PROTOCOL__host_buffer_info_t config_buffer_infos[CONTROL_PROTOCOL__MAX_CFG_CHANNELS];
uint32_t context_stream_remap_data_length;
CONTROL_PROTOCOL__stream_remap_data_t context_stream_remap_data;
uint32_t number_of_edge_layers_length;
* | | | .header = { CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ENABLE_LCU_DEFAULT, true }; |
* | | | .cluster_index = <some_cluster_index>; |
* | | | .lcu_index = <some_lcu_index>; |
+ * | | | .network_index = <some_network_index>; |
* | | | } |
* | | | CONTROL_PROTOCOL__ENABLE_LCU_DEFAULT_ACTION_t { |
* | | | .header = { CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ENABLE_LCU_DEFAULT, true }; |
* | | | .cluster_index = <some_cluster_index>; |
* | | | .lcu_index = <some_lcu_index>; |
+ * | | | .network_index = <some_network_index>; |
* | | | } |
* | | | CONTROL_PROTOCOL__ENABLE_LCU_DEFAULT_ACTION_t { |
* | | | .header = { CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ENABLE_LCU_DEFAULT, true }; |
* | | | .cluster_index = <some_cluster_index>; |
* | | | .lcu_index = <some_lcu_index>; |
+ * | | | .network_index = <some_network_index>; |
* | V | } |
* | ... | (Next action control) |
* |--------------------------------------------------------------------------------------------------|
CONTROL_PROTOCOL__ACTION_HEADER_t header;
uint8_t cluster_index;
uint8_t lcu_index;
+ uint8_t network_index;
} CONTROL_PROTOCOL__ENABLE_LCU_DEFAULT_ACTION_t;
typedef struct {
CONTROL_PROTOCOL__ACTION_HEADER_t header;
} CONTROL_PROTOCOL__ADD_DDR_BUFFERING_START_ACTION_t;
+typedef struct {
+ /* Must be first */
+ CONTROL_PROTOCOL__ACTION_HEADER_t header;
+} CONTROL_PROTOCOL__BURST_CREDITS_TASK_START_ACTION_T;
+
typedef struct {
CONTROL_PROTOCOL__TRIGGER_t trigger;
uint16_t triggers_action_count;
uint8_t state_machine_status;
uint32_t application_index_length;
uint8_t application_index;
+ uint32_t dynamic_batch_size_length;
+ uint16_t dynamic_batch_size;
} CONTROL_PROTOCOL__change_context_switch_status_request_t;
typedef struct {
typedef struct {
uint32_t application_index_length;
uint8_t application_index;
+ uint32_t dynamic_batch_size_length;
+ uint16_t dynamic_batch_size;
} CONTROL_PROTOCOL__switch_application_request_t;
typedef struct {
typedef struct {
bool is_first_control_per_context;
bool is_last_control_per_context;
- uint64_t context_cfg_base_address[CONTROL_PROTOCOL__MAX_CFG_CHANNELS];
- uint16_t context_cfg_total_descriptors[CONTROL_PROTOCOL__MAX_CFG_CHANNELS];
+ uint8_t cfg_channels_count;
+ CONTROL_PROTOCOL__host_buffer_info_t config_buffer_infos[CONTROL_PROTOCOL__MAX_CFG_CHANNELS];
CONTROL_PROTOCOL__stream_remap_data_t context_stream_remap_data;
uint8_t number_of_edge_layers;
uint8_t number_of_trigger_groups;
FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_FAILED_SETTING_OVERCURRENT_STATE)\
FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_CONTROL_UNSUPPORTED)\
FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_CONTROL_DEPRECATED)\
+ FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_CONTEXT_SWITCH_HOST_BUFFER_INFO)\
+ FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_CFG_CHANNELS_COUNT_LENGTH)\
+ FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_DYNAMIC_BATCH_SIZE_LENGTH)\
+ FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_INFER_FEATURES_LENGTH) /* DEPRECATED */\
\
FIRMWARE_MODULE__X(FIRMWARE_MODULE__POWER_MEASUREMENT)\
FIRMWARE_STATUS__X(HAILO_POWER_MEASUREMENT_STATUS_POWER_INIT_ERROR)\
FIRMWARE_STATUS__X(PCIE_SERVICE_STATUS_GLUE_LOGIC_CHANNEL_OUT_OF_RANGE)\
FIRMWARE_STATUS__X(PCIE_SERVICE_STATUS_INVALID_H2D_CHANNEL_INDEX)\
FIRMWARE_STATUS__X(PCIE_SERVICE_STATUS_INVALID_D2H_CHANNEL_INDEX)\
+ FIRMWARE_STATUS__X(PCIE_SERVICE_INVALID_INITIAL_CREDIT_SIZE)\
\
FIRMWARE_MODULE__X(FIRMWARE_MODULE__FIRMWARE_UPDATE)\
FIRMWARE_STATUS__X(FIRMWARE_UPDATE_STATUS_INVALID_PARAMETERS)\
FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_INVALID_OUTPUT_BUFFER_INDEX)\
FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_INVALID_OUTPUT_BUFFER_CLUSTER_INDEX)\
FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_INVALID_OUTPUT_BUFFER_INTERFACE)\
+ FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_ACTION_IS_NOT_SUPPORTED)\
+ FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_INVALID_CFG_CHANNELS_COUNT)\
+ FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_INVALID_HOST_BUFFER_TYPE)\
+ FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_BURST_CREDITS_TASK_IS_NOT_IDLE)\
\
FIRMWARE_MODULE__X(FIRMWARE_MODULE__D2H_EVENT_MANAGER)\
FIRMWARE_STATUS__X(HAILO_D2H_EVENT_MANAGER_STATUS_MESSAGE_HIGH_PRIORITY_QUEUE_CREATE_FAILED)\
FIRMWARE_STATUS__X(CSM_CONFIG_MANAGER_STATUS_CSM_NOT_ENABLED_WHILE_TRYING_TO_FETCH_CONFIG)\
FIRMWARE_STATUS__X(CSM_CONFIG_MANAGER_STATUS_CSM_BURST_COUNTER_IS_NOT_ZERO)\
FIRMWARE_STATUS__X(CSM_CONFIG_MANAGER_STATUS_CSM_CREDIT_COUNTER_IS_NOT_ZERO)\
+ FIRMWARE_STATUS__X(CSM_CONFIG_MANAGER_STATUS_CSM_FIFO_NOT_EMPTY)\
\
FIRMWARE_MODULE__X(FIRMWARE_MODULE__PCIE_CONFIG_MANAGER)\
FIRMWARE_STATUS__X(PCIE_CONFIG_MANAGER_STATUS_NOT_IMPLEMENTED)\
FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_NULL_ARG_PASSED)\
FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_CHANNEL_FAILED_TO_REACH_IDLE_STATE)\
FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_VDMA_MUST_BE_STOPPED_WHEN_CHECKING_IDLE)\
+ FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_EXTERNAL_DESC_COUNT_MUST_BE_POWER_OF_2)\
+ FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_TOO_MANY_DESCRIPTORS)\
+ FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_INVALID_HOST_BUFFER_TYPE)\
+ FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_DESC_PAGE_SIZE_MUST_BE_POWER_OF_2)\
+ FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_INITIAL_DESC_BIGGER_EQ_THAN_TOTAL)\
+ FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_CCB_NOT_IMPLEMENTED_OVER_PCIE)\
+ FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_CCB_BASE_ADDRESS_IS_NOT_IN_MASK)\
+ FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_INITIAL_DESC_BIGGER_THAN_TOTAL)\
+ FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_INVALID_INITIAL_CREDIT_SIZE)\
+ FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_TOO_LARGE_BYTES_IN_PATTERN)\
\
FIRMWARE_MODULE__X(FIRMWARE_MODULE__MEMORY_LOGGER)\
FIRMWARE_STATUS__X(MEMORY_LOGGER_STATUS_DEBUG_INSUFFICIENT_MEMORY)\
FIRMWARE_STATUS__X(DRAM_DMA_SERVICE_STATUS_SETUP_INTERRUPT_HANDLER_FAILED)\
FIRMWARE_STATUS__X(DRAM_DMA_SERVICE_STATUS_BURST_CREDIT_SIZE_TOO_BIG)\
FIRMWARE_STATUS__X(DRAM_DMA_SERVICE_STATUS_INVALID_CHANNEL_DMA_ADDRESS)\
+ FIRMWARE_STATUS__X(DRAM_DMA_SERVICE_STATUS_INVALID_DESC_PAGE_SIZE)\
+ FIRMWARE_STATUS__X(DRAM_DMA_SERVICE_NUM_PAGES_IS_OUT_OF_RANGE)\
+ FIRMWARE_STATUS__X(DRAM_DMA_SERVICE_INVALID_INITIAL_CREDIT_SIZE)\
+ FIRMWARE_STATUS__X(DRAM_DMA_SERVICE_TOTAL_DESCS_COUNT_IS_OUT_OF_RANGE)\
+ FIRMWARE_STATUS__X(DRAM_DMA_SERVICE_TOTAL_DESCS_COUNT_MUST_BE_POWER_OF_2)\
+ FIRMWARE_STATUS__X(DRAM_DMA_SERVICE_INVALID_DESCS_COUNT)\
+ FIRMWARE_STATUS__X(DRAM_DMA_SERVICE_DESC_PER_INTERRUPT_NOT_IN_MASK)\
\
FIRMWARE_MODULE__X(FIRMWARE_MODULE__NN_CORE_SERVICE)\
FIRMWARE_STATUS__X(NN_CORE_SERVICE_STATUS_INVALID_ARG_PASSED)\
FIRMWARE_STATUS__X(DATA_STREAM_MANAGER_WRAPPER_STATUS_INVALID_EDGE_LAYER_INDEX)\
FIRMWARE_STATUS__X(DATA_STREAM_MANAGER_WRAPPER_STATUS_INVALID_DESC_PAGE_SIZE)\
FIRMWARE_STATUS__X(DATA_STREAM_MANAGER_WRAPPER_STATUS_INVALID_EDGE_LAYER_DIRECTION)\
+ FIRMWARE_STATUS__X(DATA_STREAM_WRAPPER_STATUS_INVALID_CHANNEL_INDEX)\
+ FIRMWARE_STATUS__X(DATA_STREAM_WRAPPER_STATUS_INVALID_STREAM_INDEX)\
+ FIRMWARE_STATUS__X(DATA_STREAM_MANAGER_STATUS_INVALID_CREDIT_TYPE)\
+ FIRMWARE_STATUS__X(DATA_STREAM_MANAGER_WRAPPER_STATUS_INVALID_HOST_BUFFER_TYPE)\
+ \
+ FIRMWARE_MODULE__X(FIRMWARE_MODULE__BURST_CREDITS_TASK)\
+ FIRMWARE_STATUS__X(BURST_CREDITS_TASK_STATUS_TRYING_TO_ADD_ACTION_WHILE_NOT_IN_IDLE_STATE)\
+ FIRMWARE_STATUS__X(BURST_CREDITS_TASK_STATUS_TOO_MANY_ACTIONS)\
+ FIRMWARE_STATUS__X(BURST_CREDITS_TASK_STATUS_TRYING_TO_CHANGE_STATE_TO_INFER_WHILE_ALREADY_IN_INFER)\
+ FIRMWARE_STATUS__X(BURST_CREDITS_TASK_STATUS_INFER_REACHED_TIMEOUT)\
+ FIRMWARE_STATUS__X(BURST_CREDITS_TASK_STATUS_TASK_DEACTIVATED)\
+ \
+
typedef enum {
#define FIRMWARE_MODULE__X(module) module,
# Set firmware version
add_definitions( -DFIRMWARE_VERSION_MAJOR=4 )
-add_definitions( -DFIRMWARE_VERSION_MINOR=6 )
+add_definitions( -DFIRMWARE_VERSION_MINOR=8 )
add_definitions( -DFIRMWARE_VERSION_REVISION=0 )
message(STATUS "Building pre_build")
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_LIST_DIR}/pre_build/install
-DHAILO_EXTERNAL_DIR=${HAILO_EXTERNAL_DIR}
+ -DHAILO_OFFLINE_COMPILATION=${HAILO_OFFLINE_COMPILATION}
BUILD_ARGS
--config ${CMAKE_BUILD_TYPE} --target install ${CMAKE_EXTRA_BUILD_ARGS}
PARALLEL_BUILD
)
-# BENCHMARK_ENABLE_TESTING can be used by other 3rd party projects, therefore we define it
-# before adding projects
+# BENCHMARK_ENABLE_TESTING can be used by other 3rd party projects, therefore we define it
+# before adding projects
set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Enable testing of the benchmark library.")
add_subdirectory(external/benchmark EXCLUDE_FROM_ALL)
set(DRIVER_INC_DIR ${PROJECT_SOURCE_DIR}/hailort/drivers/common)
if(HAILO_BUILD_PYBIND)
+ if(NOT PYTHON_EXECUTABLE AND PYBIND11_PYTHON_VERSION)
+ # PYBIND11_PYTHON_VERSION is prioritized (not virtual environment) if PYTHON_EXECUTABLE is not set.
+ # See https://pybind11.readthedocs.io/en/stable/changelog.html#v2-6-0-oct-21-2020
+ if(${CMAKE_VERSION} VERSION_LESS "3.12.0")
+ find_package(PythonInterp ${PYBIND11_PYTHON_VERSION} REQUIRED)
+ set(PYTHON_EXECUTABLE ${Python_EXECUTABLE})
+ else()
+ find_package(Python3 ${PYBIND11_PYTHON_VERSION} REQUIRED EXACT COMPONENTS Interpreter Development)
+ set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE})
+ endif()
+ endif()
add_subdirectory(external/pybind11 EXCLUDE_FROM_ALL)
endif()
add_subdirectory(external/Catch2 EXCLUDE_FROM_ALL)
add_subdirectory(external/DotWriter EXCLUDE_FROM_ALL)
add_subdirectory(external/spdlog EXCLUDE_FROM_ALL)
set_target_properties(spdlog PROPERTIES POSITION_INDEPENDENT_CODE ON)
-add_subdirectory(common)
-add_subdirectory(libhailort)
-add_subdirectory(hailortcli)
+if(CMAKE_SYSTEM_NAME STREQUAL QNX)
+ add_library(pevents STATIC EXCLUDE_FROM_ALL external/pevents/src/pevents.cpp)
+ target_include_directories(pevents PUBLIC external/pevents/src)
+ target_compile_definitions(pevents PRIVATE -DWFMO)
+endif()
-# copy files to venv
-if(HAILO_BUILD_PYBIND AND HAILO_BUILD_PYHAILORT_VENV)
- set(VENV_DRIVERS_DIR ${CMAKE_SOURCE_DIR}/hailort/libhailort/bindings/python/platform/hailo_platform/drivers/hailort/)
- set(PYHAILORT_FILES_TO_COPY
- $<TARGET_FILE:_pyhailort>
- )
- set(VENV_PYHAILORT_INTERNAL_DIR ${CMAKE_SOURCE_DIR}/platform_internals/hailo_platform_internals/pyhailort/)
- set(PYHAILORT_INTERNAL_FILES_TO_COPY
- $<TARGET_FILE:_pyhailort_internal>
+# microprofile
+if(HAILO_MICROPROFILE)
+ add_library(microprofile STATIC EXCLUDE_FROM_ALL external/microprofile/microprofile.cpp)
+ set_target_properties(microprofile PROPERTIES
+ CXX_STANDARD 11
+ CXX_STANDARD_REQUIRED YES
+ POSITION_INDEPENDENT_CODE ON
)
- add_custom_target(
- pyhailort_venv ALL
- COMMAND ${CMAKE_COMMAND} -E copy ${PYHAILORT_FILES_TO_COPY} ${VENV_DRIVERS_DIR}
- COMMAND ${CMAKE_COMMAND} -E copy ${PYHAILORT_INTERNAL_FILES_TO_COPY} ${VENV_PYHAILORT_INTERNAL_DIR}
+ target_compile_definitions(microprofile
+ PRIVATE
+ -DMICROPROFILE_WEBSERVER=1
+ -DMICROPROFILE_GPU_TIMERS=0
+ -DMICROPROFILE_NAME_MAX_LEN=256
+ PUBLIC
+ -DMICROPROFILE_ENABLED=1
)
- add_dependencies(pyhailort_venv libhailort _pyhailort)
+ target_include_directories(microprofile PUBLIC external/microprofile)
+else()
+ add_library(microprofile INTERFACE)
+ target_compile_definitions(microprofile INTERFACE -DMICROPROFILE_ENABLED=0)
+ target_include_directories(microprofile INTERFACE external/microprofile)
endif()
+add_subdirectory(common)
+add_subdirectory(libhailort)
+add_subdirectory(hailortcli)
+
if(HAILO_WIN_DRIVER)
add_subdirectory(drivers/win)
add_subdirectory(packaging)
| CLI11 | University of Cincinnati | 3-Clause BSD | 1.7 | Cloned entire package | https://github.com/CLIUtils/CLI11 |
| Catch2 | Catch2 Authors | BSL-1.0 | 2.13.7 | Cloned entire package | https://github.com/catchorg/Catch2 |
| protobuf | Google Inc. | BSD | 3.11.4 | Cloned entire package | https://github.com/protocolbuffers/protobuf |
-| pybind11 | Wenzel Jakob | BSD | 2.3.0 | Cloned entire package | https://github.com/pybind/pybind11 |
+| pybind11 | Wenzel Jakob | BSD | 2.6.2 | Cloned entire package | https://github.com/pybind/pybind11 |
| spdlog | Gabi Melman | MIT | 1.6.1 | Cloned entire package | https://github.com/gabime/spdlog |
| folly | Facebook, Inc. and its affiliates | Apache License 2.0 | v2020.08.17.00 | Copied only the file `folly/TokenBucket.h` | https://github.com/facebook/folly |
| nlohmann_json_cmake_fetchcontent | ArthurSonzogni | MIT License | v3.9.1 | Cloned entire package | https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent |
| readerwriterqueue | Cameron Desrochers | Simplified BSD | 1.0.3 | Cloned entire package | https://github.com/cameron314/readerwriterqueue |
| DotWriter | John Vilk | MIT License | master | Cloned entire package (forked) | https://github.com/jvilk/DotWriter |
| benchmark | Google Inc. | Apache License 2.0 | 1.6.0 | Cloned entire package | https://github.com/google/benchmark.git |
-| md5 | Alexander Peslyak | cut-down BSD | - | Copied code from website | http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 |
\ No newline at end of file
+| md5 | Alexander Peslyak | cut-down BSD | - | Copied code from website | http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 |
+| pevents | Mahmoud Al-Qudsi | MIT License | master | Cloned entire package | https://github.com/neosmart/pevents.git |
+| microprofile | Jonas Meyer | Unlicense License | 3.1 | Cloned entire package | https://github.com/jonasmr/microprofile |
return CB_HEAD(m_circ) == CB_TAIL(m_circ);
}
+ bool full()
+ {
+ return 0 == CB_AVAIL(m_circ, CB_HEAD(m_circ), CB_TAIL(m_circ));
+ }
+
private:
circbuf_t m_circ;
std::vector<T> m_array;
};
using LatencyMeterPtr = std::shared_ptr<LatencyMeter>;
+using LatencyMetersMap = std::map<std::string, LatencyMeterPtr>;
} /* namespace hailort */
return readdir(m_dir);
}
-#if defined(__unix__)
+#if defined(__linux__)
Expected<std::vector<std::string>> Filesystem::get_files_in_dir_flat(const std::string &dir_path)
{
return (container.find(value) != container.end());
}
+template <class T>
+class unlock_guard {
+public:
+ unlock_guard(T &lock) : m_lock(lock) {
+ m_lock.unlock();
+ }
+
+ ~unlock_guard() {
+ m_lock.lock();
+ }
+
+ unlock_guard(const unlock_guard&) = delete;
+ unlock_guard& operator=(const unlock_guard&) = delete;
+
+private:
+ T &m_lock;
+};
+
// From https://stackoverflow.com/questions/57092289/do-stdmake-shared-and-stdmake-unique-have-a-nothrow-version
template <class T, class... Args>
static inline std::unique_ptr<T> make_unique_nothrow(Args&&... args)
return power_of_2;
}
+template<class K, class V>
+static uint32_t get_max_value_of_unordered_map(const std::unordered_map<K, V> &map)
+{
+ uint32_t max_count = 0;
+ for (auto &name_counter_pair : map) {
+ if (name_counter_pair.second > max_count) {
+ max_count = name_counter_pair.second;
+ }
+ }
+ return max_count;
+}
+
} /* namespace hailort */
#endif /* HAILO_UTILS_H_ */
\ No newline at end of file
#ifdef _MSC_VER
#if !defined(bool) && !defined(__cplusplus)
typedef uint8_t bool;
-#endif
+#endif // !defined(bool) && !defined(__cplusplus)
+
#if !defined(INT_MAX)
#define INT_MAX 0x7FFFFFFF
-#endif
-#else
+#endif // !defined(INT_MAX)
+
+#elif defined(__linux__) // #ifdef _MSC_VER
#ifndef __KERNEL__
// include the userspace headers only if this file is included by user space program
// It is discourged to include them when compiling the driver (https://lwn.net/Articles/113349/)
#include <linux/types.h>
#include <linux/limits.h>
#include <linux/kernel.h>
-#endif
+#endif // ifndef __KERNEL__
-#if defined(__unix__)
#include <linux/ioctl.h>
-#endif
#define _IOW_ _IOW
#define _IOR_ _IOR
#define HAILO_GENERAL_IOCTL_MAGIC 'g'
#define HAILO_VDMA_IOCTL_MAGIC 'v'
#define HAILO_WINDOWS_IOCTL_MAGIC 'w'
+
+#elif defined(__QNX__) // #ifdef _MSC_VER
+#include <devctl.h>
+#include <stdint.h>
+#include <sys/types.h>
+// defines for devctl
+#define _IOW_ __DIOF
+#define _IOR_ __DIOT
+#define _IOWR_ __DIOTF
+#define _IO_ __DION
+#define HAILO_GENERAL_IOCTL_MAGIC _DCMD_ALL
+#define HAILO_VDMA_IOCTL_MAGIC _DCMD_MISC
+
+#else // #ifdef _MSC_VER
+#error "unsupported platform!"
#endif
#pragma pack(push, 1)
};
/* structure used in ioctl HAILO_BAR_TRANSFER */
+// Max bar transfer size gotten from ATR0_TABLE_SIZE
+#define MAX_BAR_TRANSFER_LENGTH (4096)
+
enum hailo_transfer_direction {
TRANSFER_READ = 0,
TRANSFER_WRITE,
uint32_t bar_index; // in
off_t offset; // in
size_t count; // in
- void* buffer; // in/out
+ uint8_t buffer[MAX_BAR_TRANSFER_LENGTH]; // in/out
};
/* structure used in ioctl HAILO_VDMA_CHANNEL_REGISTERS */
};
/* structure used in ioctl HAILO_READ_NOTIFICATION */
+#define MAX_NOTIFICATION_LENGTH (1500)
+
struct hailo_d2h_notification {
size_t buffer_len; // out
- uint8_t buffer[MAX_CONTROL_LENGTH]; // out
+ uint8_t buffer[MAX_NOTIFICATION_LENGTH]; // out
};
enum hailo_board_type {
uint32_t minor_version;
uint32_t revision_version;
};
+
+/* structure used in ioctl HAILO_READ_LOG */
+#define MAX_FW_LOG_BUFFER_LENGTH (512)
+
struct hailo_read_log_params {
- enum hailo_cpu_id cpu_id; // in
- uint8_t *buffer; // out
- size_t buffer_size; // in
- size_t read_bytes; // out
+ enum hailo_cpu_id cpu_id; // in
+ uint8_t buffer[MAX_FW_LOG_BUFFER_LENGTH]; // out
+ size_t buffer_size; // in
+ size_t read_bytes; // out
};
-struct hailo_allocate_buffer_params {
+struct hailo_allocate_low_memory_buffer_params {
size_t buffer_size; // in
uintptr_t buffer_handle; // out
};
bool in_use; // out
};
+struct hailo_allocate_continuous_buffer_params {
+ size_t buffer_size; // in
+ uintptr_t buffer_handle; // out
+ uint64_t dma_address; // out
+};
+
#pragma pack(pop)
enum hailo_general_ioctl_code {
HAILO_GENERAL_IOCTL_MAX_NR,
};
-#define HAILO_BAR_TRANSFER _IOW_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_BAR_TRANSFER_CODE, struct hailo_bar_transfer_params)
+#define HAILO_BAR_TRANSFER _IOWR_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_BAR_TRANSFER_CODE, struct hailo_bar_transfer_params)
#define HAILO_FW_CONTROL _IOWR_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_FW_CONTROL_CODE, struct hailo_fw_control)
#define HAILO_READ_NOTIFICATION _IOW_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_READ_NOTIFICATION_CODE, struct hailo_d2h_notification)
#define HAILO_DISABLE_NOTIFICATION _IO_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_DISABLE_NOTIFICATION_CODE)
HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC_CODE,
HAILO_VDMA_LOW_MEMORY_BUFFER_FREE_CODE,
HAILO_MARK_AS_IN_USE_CODE,
+ HAILO_VDMA_CONTINUOUS_BUFFER_ALLOC_CODE,
+ HAILO_VDMA_CONTINUOUS_BUFFER_FREE_CODE,
// Must be last
HAILO_VDMA_IOCTL_MAX_NR,
#define HAILO_DESC_LIST_RELEASE _IO_(HAILO_VDMA_IOCTL_MAGIC, HAILO_DESC_LIST_RELEASE_CODE)
#define HAILO_DESC_LIST_BIND_VDMA_BUFFER _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_DESC_LIST_BIND_VDMA_BUFFER_CODE, struct hailo_desc_list_bind_vdma_buffer_params)
-#define HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC_CODE, struct hailo_allocate_buffer_params)
+#define HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC_CODE, struct hailo_allocate_low_memory_buffer_params)
#define HAILO_VDMA_LOW_MEMORY_BUFFER_FREE _IO_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_LOW_MEMORY_BUFFER_FREE_CODE)
#define HAILO_MARK_AS_IN_USE _IOW_(HAILO_VDMA_IOCTL_MAGIC, HAILO_MARK_AS_IN_USE_CODE, struct hailo_mark_as_in_use_params)
+#define HAILO_VDMA_CONTINUOUS_BUFFER_ALLOC _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CONTINUOUS_BUFFER_ALLOC_CODE, struct hailo_allocate_continuous_buffer_params)
+#define HAILO_VDMA_CONTINUOUS_BUFFER_FREE _IO_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CONTINUOUS_BUFFER_FREE_CODE)
+
+
enum hailo_windows_ioctl_code {
HAILO_WINDOWS_DESC_LIST_MMAP_CODE,
--- /dev/null
+/*++
+
+Module Name:
+
+ public.h
+
+Abstract:
+
+ This module contains the common declarations shared by driver
+ and user applications.
+
+Environment:
+
+ user and kernel
+
+--*/
+
+//
+// Define an Interface Guid so that apps can find the device and talk to it.
+//
+
+DEFINE_GUID (GUID_DEVINTERFACE_HailoKM,
+ 0xd88d31f1,0xfede,0x4e71,0xac,0x2a,0x6c,0xe0,0x01,0x8c,0x15,0x01);
+// {d88d31f1-fede-4e71-ac2a-6ce0018c1501}
+
+#define HAILO_IOCTL_COMMON CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_FUNC(x) (((x) >> 2) & 0xfff)
+#define NUMBER_OF_PARAMETERS(code) ((code) & 0xf)
+#define NUMBER_OF_PARAMETERS_FLEXIBLE 0xf
+
+struct tCommonHailoIoctlParam
+{
+ ULONG ulCode : 24;
+ ULONG fResponse : 1;
+ ULONG fUseLL : 1;
+ ULONG ulParamNum : 4;
+ union {
+ ULONG ulInputs[4];
+ ULONGLONG llInputs[2];
+ };
+ union {
+ ULONG ulOutputs[4];
+ ULONGLONG llOutputs[2];
+ };
+};
+
+#define HAILO_CMD_FW_LOAD 0x0010
+#define HAILO_CMD_READ_CFG 0x0011
+#define HAILO_CMD_SW_RESET 0x0020
+#define HAILO_CMD_READ_INTERRUPT_BAR 0x0021
+#define HAILO_CMD_READ_FW_STATUS 0x0030
+#define HAILO_CMD_READ_FIRMWARE_BAR 0x0031
+#define HAILO_CMD_CANCEL_READ 0x0040
+#define HAILO_CMD_READ_RP_CFG 0x0041
+#define HAILO_CMD_UNMAP_BUFFER 0x0050
+#define HAILO_CMD_MAP_BUFFER 0x0051
+#define HAILO_CMD_FREE_MEMORY 0x0060
+#define HAILO_CMD_ALLOC_MEMORY 0x0061
+#define HAILO_CMD_ABORT_ALL 0x0070
+
+#define HAILO_IOCTL_COMPATIBLE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
+struct tCompatibleHailoIoctlParam
+{
+ union {
+ struct {
+ ULONG Size : 16;
+ ULONG Code : 8;
+ ULONG Type : 6;
+ ULONG Read : 1;
+ ULONG Write : 1;
+ } bits;
+ ULONG value;
+ } u;
+};
+
+#define HAILO_GENERAL_IOCTL_MAGIC 0
+#define HAILO_VDMA_IOCTL_MAGIC 1
+#define HAILO_WINDOWS_IOCTL_MAGIC 2
+
+
+
+static ULONG FORCEINLINE _IOC_(ULONG nr, ULONG type, ULONG size, bool read, bool write)
+{
+ tCompatibleHailoIoctlParam param;
+ param.u.bits.Code = nr;
+ param.u.bits.Size = size;
+ param.u.bits.Type = type;
+ param.u.bits.Read = read ? 1 : 0;
+ param.u.bits.Write = write ? 1 : 0;
+ return param.u.value;
+}
+
+#define _IOW_(type,nr,size) _IOC_(nr, type, sizeof(size), true, false)
+#define _IOR_(type,nr,size) _IOC_(nr, type, sizeof(size), false, true)
+#define _IOWR_(type,nr,size) _IOC_(nr, type, sizeof(size), true, true)
+#define _IO_(type,nr) _IOC_(nr, type, 0, false, false)
+
+#include "..\..\common\hailo_ioctl_common.h"
+
+struct tCompatibleHailoIoctlData
+{
+ tCompatibleHailoIoctlParam Parameters;
+ ULONG_PTR Value;
+ union {
+ hailo_bar_transfer_params BarTransfer;
+ hailo_vdma_channel_enable_params ChannelEnable;
+ hailo_vdma_channel_disable_params ChannelDisable;
+ hailo_vdma_channel_wait_params ChannelWait;
+ hailo_vdma_channel_abort_params ChannelAbort;
+ hailo_vdma_channel_clear_abort_params ChannelClearAbort;
+ hailo_vdma_buffer_sync_params VdmaBufferSync;
+ hailo_fw_control FirmwareControl;
+ hailo_vdma_buffer_map_params VdmaBufferMap;
+ hailo_desc_list_create_params DescListCreate;
+ hailo_desc_list_bind_vdma_buffer_params DescListBind;
+ hailo_d2h_notification D2HNotification;
+ hailo_device_properties DeviceProperties;
+ hailo_driver_info DriverInfo;
+ hailo_channel_registers_params ChannelRegisters;
+ hailo_windows_desc_list_mmap_params DescListMmap;
+ hailo_read_log_params ReadLog;
+ hailo_mark_as_in_use_params MarkAsInUse;
+ } Buffer;
+};
--- /dev/null
+#ifndef _HAILO_PCIE_VERSION_H_
+#define _HAILO_PCIE_VERSION_H_
+
+#include "..\..\common\hailo_pcie_version.h"
+
+#define STRINGIFY_EXPANDED( x ) #x
+#define STRINGIFY_NUMBER( x ) STRINGIFY_EXPANDED(x)
+#define HAILO_DRV_VER STRINGIFY_NUMBER(HAILO_DRV_VER_MAJOR) "." STRINGIFY_NUMBER(HAILO_DRV_VER_MINOR) "." STRINGIFY_NUMBER(HAILO_DRV_VER_REVISION)
+
+#endif /* _HAILO_PCIE_VERSION_H_ */
cmake_minimum_required(VERSION 3.0.0)
+include(GNUInstallDirs)
+
set(HAILORTCLI_CPP_FILES
hailortcli.cpp
command.cpp
udp_rate_limiter_command.cpp
# TODO: We dont compile download_action_list_command on windows, as it uses packed enums (HRT-5919)
download_action_list_command.cpp
-
)
endif()
)
target_compile_options(hailortcli PRIVATE ${HAILORT_COMPILE_OPTIONS})
set_property(TARGET hailortcli PROPERTY CXX_STANDARD 14)
-set_property(TARGET hailortcli PROPERTY INSTALL_RPATH "$ORIGIN") # Need to add "${CMAKE_INSTALL_LIBDIR}" when installing with cmake to /usr/local
+set_property(TARGET hailortcli PROPERTY INSTALL_RPATH "$ORIGIN" "../lib/") # Link with a relative libhailort
target_link_libraries(hailortcli libhailort CLI11::CLI11 nlohmann_json spdlog::spdlog readerwriterqueue)
target_link_libraries(hailortcli DotWriter)
+# TODO: Remove microprofile after removing pipeline.cpp from hailortcli sources
+target_link_libraries(hailortcli microprofile)
+
if(WIN32)
target_link_libraries(hailortcli Ws2_32 Iphlpapi Shlwapi)
+elseif(CMAKE_SYSTEM_NAME STREQUAL QNX)
+ target_link_libraries(hailortcli pevents)
endif()
target_include_directories(hailortcli
PRIVATE
m_app->add_option("hef", m_params.hef_path, "Path of the HEF to load")
->check(CLI::ExistingFile)
->required();
- m_app->add_option("-t, --time-to-run", m_time, "Measurement time in seconds per hw_only/streaming/latency measurement mode")
+ m_app->add_option("-t, --time-to-run", m_params.time_to_run, "Measurement time in seconds per hw_only/streaming/latency measurement mode")
->check(CLI::PositiveNumber)
->default_val(15);
m_app->add_option("--no-power", m_not_measure_power, "Skip power measurement, even if the platform supports it. The default value is False")
->default_val("false");
m_app->add_option("--batch-size", m_params.batch_size, "Inference batch size (default is 1)")
->default_val(1);
+ m_app->add_option("--power-mode", m_params.power_mode,
+ "Core power mode (PCIE only; ignored otherwise)")
+ ->transform(HailoCheckedTransformer<hailo_power_mode_t>({
+ { "performance", hailo_power_mode_t::HAILO_POWER_MODE_PERFORMANCE },
+ { "ultra_performance", hailo_power_mode_t::HAILO_POWER_MODE_ULTRA_PERFORMANCE }
+ }))
+ ->default_val("performance");
m_app->add_option("--input-files", m_params.inputs_name_and_file_path, " The input files need to be in UINT8 before transformations.")
->check(InputNameToFileMap);
m_app->add_option("--csv", m_csv_file_path, "If set print the output as csv to the specified path");
auto streaming_mode_info = fps_streaming_mode();
CHECK_EXPECTED_AS_STATUS(streaming_mode_info, "FPS in streaming mode failed");
+ // TODO - HRT-6931 - measure latnecy only in the case of single device.
std::cout << "Measuring HW Latency" << std::endl;
auto latency_info = latency();
CHECK_EXPECTED_AS_STATUS(latency_info, "Latency measuring failed");
m_params.power_measurement.measure_power = false;
m_params.measure_latency = false;
m_params.mode = InferMode::HW_ONLY;
- m_params.time_to_run = m_time;
return run_command_hef(m_params);
}
m_params.measure_latency = false;
m_params.transform.transform = true;
m_params.transform.quantized = false;
- m_params.time_to_run = m_time;
return run_command_hef(m_params);
}
m_params.mode = InferMode::STREAMING;
m_params.transform.transform = true;
m_params.transform.quantized = false;
- m_params.time_to_run = m_time;
return run_command_hef(m_params);
}
\ No newline at end of file
inference_runner_params m_params;
bool m_not_measure_power;
- uint32_t m_time;
std::string m_csv_file_path;
};
hailo_status DeviceCommand::execute()
{
+ if ((DeviceType::PCIE == m_device_params.device_type ) &&
+ ("*" == m_device_params.pcie_params.pcie_bdf)) {
+ return execute_on_all_pcie_devices();
+ }
auto device = create_device(m_device_params);
if (!device) {
return device.status();
return execute_on_device(*device.value());
}
-PcieDeviceCommand::PcieDeviceCommand(CLI::App *app) :
- Command(app)
-{
- auto group = app->add_option_group("PCIE Device Options");
-
- // PCIe options
- group->add_option("-s,--bdf", m_pcie_device_params.pcie_bdf,
- "Device id ([<domain>]:<bus>:<device>.<func>, same as in lspci command)")
- ->default_val("");
-}
-
-hailo_status PcieDeviceCommand::execute()
+hailo_status DeviceCommand::execute_on_all_pcie_devices()
{
- auto device = create_pcie_device(m_pcie_device_params);
- if (!device) {
- return device.status();
+ auto status = HAILO_SUCCESS; // Best effort
+ auto all_devices_infos = Device::scan_pcie();
+ if (!all_devices_infos) {
+ return all_devices_infos.status();
}
+ for (auto &dev_info : all_devices_infos.value()) {
+ auto device = Device::create_pcie(dev_info);
+ if (!device) {
+ return device.status();
+ }
- return execute_on_device(*device.value());
+ auto execute_status = execute_on_device(*device.value());
+ if (HAILO_SUCCESS != execute_status) {
+ std::cerr << "Failed to execute on device: " << device.value()->get_dev_id() << ". status= " << execute_status << std::endl;
+ status = execute_status;
+ }
+ }
+ return status;
}
return m_app->parsed();
}
- void set_description(const std::string &new_desc)
- {
- m_app->description(new_desc);
- }
-
void set_footer(const std::string &new_footer)
{
m_app->footer(new_footer);
protected:
virtual hailo_status execute_on_device(Device &device) = 0;
+ hailo_status execute_on_all_pcie_devices();
private:
hailo_device_params m_device_params;
};
-class PcieDeviceCommand : public Command {
-public:
- explicit PcieDeviceCommand(CLI::App *app);
- virtual hailo_status execute() override final;
-
-protected:
- virtual hailo_status execute_on_device(Device &device) = 0;
-
-private:
- hailo_pcie_params m_pcie_device_params;
-};
-
#endif /* _HAILO_COMMAND_HPP_ */
\ No newline at end of file
#include "md5.h"
#include <iostream>
+#include <iomanip>
constexpr int DownloadActionListCommand::INVALID_NUMERIC_VALUE;
{
static const char *JSON_SUFFIX = ".json";
m_app->add_option("--output-file", m_output_file_path, "Output file path")
- ->default_val("context_action_list.json")
+ ->default_val("runtime_data.json")
->check(FileSuffixValidator(JSON_SUFFIX));
}
return HAILO_SUCCESS;
}
+hailo_status DownloadActionListCommand::set_batch_to_measure(Device &device, uint16_t batch_to_measure)
+{
+ return device.set_context_action_list_timestamp_batch(batch_to_measure);
+}
+
hailo_status DownloadActionListCommand::execute_on_device(Device &device)
{
return execute(device, m_output_file_path);
std::stringstream hexdigest;
for (uint32_t i = 0; i < ARRAY_ENTRIES(md5_sum); i++) {
// cast to int needed for proper formatting
- hexdigest << std::hex << static_cast<int>(md5_sum[i]);
+ static const int NUM_HEX_DIGITS_IN_UNIT8 = 2;
+ hexdigest << std::hex << std::setfill('0') << std::setw(NUM_HEX_DIGITS_IN_UNIT8) << static_cast<int>(md5_sum[i]);
}
return hexdigest.str();
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__application_change_interrupt_data_t *>(action);
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__application_change_interrupt_data_t);
break;
- case CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_VDMA_DESCRIPTORS:
- data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__read_vdma_action_data_t *>(action);
- action_length_local = sizeof(CONTEXT_SWITCH_DEFS__read_vdma_action_data_t);
+ case CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_CFG_CHANNEL_DESCRIPTORS:
+ data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__fetch_cfg_channel_descriptors_action_data_t *>(action);
+ action_length_local = sizeof(CONTEXT_SWITCH_DEFS__fetch_cfg_channel_descriptors_action_data_t);
break;
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_CCW_BURSTS:
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__fetch_ccw_bursts_action_data_t *>(action);
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__deactivate_vdma_channel_action_data_t *>(action);
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__deactivate_vdma_channel_action_data_t);
break;
+ case CONTEXT_SWITCH_DEFS__ACTION_TYPE_VALIDATE_VDMA_CHANNEL:
+ data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__validate_vdma_channel_action_data_t *>(action);
+ action_length_local = sizeof(CONTEXT_SWITCH_DEFS__validate_vdma_channel_action_data_t);
+ break;
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_LCU_DEFAULT:
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t *>(action);
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t);
data_json = json({});
action_length_local = 0;
break;
+ case CONTEXT_SWITCH_DEFS__ACTION_TYPE_BURST_CREDITS_TASK_START:
+ data_json = json({});
+ action_length_local = 0;
+ break;
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_CFG_CHANNEL:
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__activate_cfg_channel_t *>(action);
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__activate_cfg_channel_t);
return network_group_list_json;
}
-void to_json(json& j, const CONTEXT_SWITCH_DEFS__read_vdma_action_data_t& data) {
+void to_json(json& j, const CONTEXT_SWITCH_DEFS__fetch_cfg_channel_descriptors_action_data_t& data) {
j = json{{"descriptors_count", data.descriptors_count}, {"channel_index", data.cfg_channel_number}};
}
// To be used from external commands
static hailo_status execute(Device &device, const std::string &output_file_path,
const ConfiguredNetworkGroupVector &network_groups={}, const std::string &hef_file_path="");
+ static hailo_status set_batch_to_measure(Device &device, uint16_t batch_to_measure);
protected:
virtual hailo_status execute_on_device(Device &device) override;
// JSON serialization
NLOHMANN_JSON_SERIALIZE_ENUM(CONTEXT_SWITCH_DEFS__ACTION_TYPE_t, {
- {CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_VDMA_DESCRIPTORS, "fetch_vdma_descriptors"},
+ {CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_CFG_CHANNEL_DESCRIPTORS, "fetch_cfg_channel_descriptors"},
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_TRIGGER_SEQUENCER, "trigger_sequencer"},
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_DATA_FROM_VDMA_CHANNEL, "fetch_data_from_vdma_channel"},
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_LCU_DEFAULT, "enable_lcu_default"},
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_DDR_BUFFER_INPUT, "activate_ddr_buffer_input"},
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_DDR_BUFFER_OUTPUT, "activate_ddr_buffer_output"},
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_DEACTIVATE_VDMA_CHANNEL, "deactivate_vdma_channel"},
+ {CONTEXT_SWITCH_DEFS__ACTION_TYPE_VALIDATE_VDMA_CHANNEL, "validate_vdma_channel"},
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_CHANGE_VDMA_TO_STREAM_MAPPING, "change_vdma_to_stream_mapping"},
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_ADD_DDR_PAIR_INFO, "add_ddr_pair_info"},
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_DDR_BUFFERING_START, "ddr_buffering_start"},
+ {CONTEXT_SWITCH_DEFS__ACTION_TYPE_BURST_CREDITS_TASK_START, "burst_credits_task_start"},
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_LCU_INTERRUPT, "lcu_interrupt"},
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_SEQUENCER_DONE_INTERRUPT, "sequencer_done_interrupt"},
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_INPUT_CHANNEL_TRANSFER_DONE_INTERRUPT, "input_channel_transfer_done_interrupt"},
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__repeated_action_header_t, count, last_executed, sub_action_type);
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__trigger_sequencer_action_data_t, cluster_index);
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__deactivate_vdma_channel_action_data_t, vdma_channel_index);
+NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__validate_vdma_channel_action_data_t, vdma_channel_index);
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__fetch_data_action_data_t, vdma_channel_index, stream_index);
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__add_ddr_pair_info_action_data_t, h2d_vdma_channel_index, d2h_vdma_channel_index);
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__vdma_dataflow_interrupt_data_t, vdma_channel_index);
void to_json(json& j, const CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t& data);
void to_json(json& j, const CONTEXT_SWITCH_DEFS__enable_lcu_action_non_default_data_t& data);
void to_json(json& j, const CONTEXT_SWITCH_DEFS__disable_lcu_action_data_t& data);
-void to_json(json& j, const CONTEXT_SWITCH_DEFS__read_vdma_action_data_t& data);
+void to_json(json& j, const CONTEXT_SWITCH_DEFS__fetch_cfg_channel_descriptors_action_data_t& data);
void to_json(json& j, const CONTEXT_SWITCH_DEFS__fetch_ccw_bursts_action_data_t& data);
void to_json(json& j, const CONTEXT_SWITCH_DEFS__change_vdma_to_stream_mapping_data_t& data);
void to_json(json& j, const CONTEXT_SWITCH_DEFS__lcu_interrupt_data_t& data);
--- /dev/null
+{
+ "network":
+ {
+ "static_netmask": "255.255.255.0",
+ "should_use_dhcp": false,
+ "mac_address": "80:00:DE:AD:BE:EF"
+ },
+ "system":
+ {
+ "name": "Hailo-8",
+ "supported_aspm_states": "ASPM L1 ONLY",
+ "temperature_throttling_enable": true
+ }
+}
{\r
add_subcommand<FwControlIdentifyCommand>();\r
add_subcommand<FwControlResetCommand>();\r
-\r
- // TODO: Remove scan as a subcommand of fw_control_subcommand (HRT-2676)\r
- // Can also remove Command::set_description function after this, and the return value of `add_subcommand`\r
- auto &scan = add_subcommand<ScanSubcommand>();\r
- scan.set_description("Alias for root-level 'scan' command (i.e. 'hailortcli scan...')\n"\r
- "Note: 'scan' as a sub-command of 'fw-control' is deprecated; use 'hailortcli scan' instead\n"\r
- " (or 'hailo scan' when using the 'hailo' command).");\r
-\r
add_subcommand<FwControlTestMemoriesCommand>();\r
// TODO: Support on windows (HRT-5919)\r
#if defined(__GNUC__)\r
- // TODO: Unhide (HRT-6035)\r
- static const bool HIDDEN = true;\r
- add_subcommand<DownloadActionListCommand>(HIDDEN);\r
+ add_subcommand<DownloadActionListCommand>();\r
#endif\r
}\r
\r
#include "hailortcli.hpp"\r
#include "command.hpp"\r
-// TODO: Remove scan as a subcommand of fw_control_subcommand (HRT-2676)\r
-#include "scan_command.hpp"\r
#if defined(__GNUC__)\r
// TODO: Support on windows (HRT-5919)\r
#include "download_action_list_command.hpp"\r
auto group = app->add_option_group("Device Options");
- // TODO: `--target` and `udp` DeviceType::ETH are for backwards compatibility with the python implemention (`hailo`)
- // TODO: Remove them (HRT-2676)
const HailoCheckedTransformer<DeviceType> device_type_transformer({
{ "pcie", DeviceType::PCIE },
{ "eth", DeviceType::ETH },
- { "udp", DeviceType::ETH },
});
auto *device_type_option = group->add_option("-d,--device-type,--target", device_params.device_type,
"Device type to use\n"
- "Default is pcie.\n"
- "Note: 'udp' is an alias for 'eth'.")
+ "Default is pcie.")
->transform(device_type_transformer);
- std::vector<DeprecationActionPtr> actions{ std::make_shared<ValueDeprecation>(device_type_option, "udp", "eth") };
- hailo_deprecate_options(app, actions, false);
-
// PCIe options
auto *pcie_bdf_option = group->add_option("-s,--bdf", device_params.pcie_params.pcie_bdf,
- "Device id ([<domain>]:<bus>:<device>.<func>, same as in lspci command)")
+ "Device id ([<domain>]:<bus>:<device>.<func>, same as in lspci command).\n" \
+ "In order to run on all PCIe devices connected to the machine one-by-one, use '*' (instead of device id).")
->default_val("");
// Ethernet options
});
}
+static bool do_versions_match()
+{
+ hailo_version_t libhailort_version = {};
+ auto status = hailo_get_library_version(&libhailort_version);
+ if (HAILO_SUCCESS != status) {
+ std::cerr << "Failed to get libhailort version" << std::endl;
+ return false;
+ }
+
+ bool versions_match = ((HAILORT_MAJOR_VERSION == libhailort_version.major) &&
+ (HAILORT_MINOR_VERSION == libhailort_version.minor) &&
+ (HAILORT_REVISION_VERSION == libhailort_version.revision));
+ if (!versions_match) {
+ std::cerr << "libhailort version (" <<
+ libhailort_version.major << "." << libhailort_version.minor << "." << libhailort_version.revision <<
+ ") does not match HailoRT-CLI version (" <<
+ HAILORT_MAJOR_VERSION << "." << HAILORT_MINOR_VERSION << "." << HAILORT_REVISION_VERSION << ")" << std::endl;
+ return false;
+ }
+ return true;
+}
+
class HailoRTCLI : public ContainerCommand {
public:
HailoRTCLI(CLI::App *app) : ContainerCommand(app)
m_app->add_flag_callback("-v,--version",
[] () {
- std::cout << "hailortcli version " <<
+ std::cout << "HailoRT-CLI version " <<
HAILORT_MAJOR_VERSION << "." << HAILORT_MINOR_VERSION << "." << HAILORT_REVISION_VERSION << std::endl;
// throw CLI::Success to stop parsing and not failing require_subcommand(1) we set earlier
throw (CLI::Success{});
};
int main(int argc, char** argv) {
+ if (!do_versions_match()) {
+ return -1;
+ }
auto console_sink = std::make_shared<spdlog::sinks::stderr_color_sink_mt>();
console_sink->set_level(spdlog::level::info);
console_sink->set_pattern("[%n] [%^%l%$] %v");
} while (0)
struct hailo_pcie_params {
- std::string pcie_bdf; // if empty use the first scanned
+ std::string pcie_bdf; // if empty use the first scanned. if '*', run on all devices on the machine one-by-one
};
struct hailo_eth_params {
#include "power_measurement_command.hpp"
#include <thread>
-#define POWER_MEASUREMENT_DELAY_MS(__sample_period, __average_factor) \
- (static_cast<uint32_t>((__sample_period) / 1000.0 * (__average_factor) * 2 * 1.2))
-
PowerMeasurementSubcommand::PowerMeasurementSubcommand(CLI::App &parent_app) :
DeviceCommand(parent_app.add_subcommand("measure-power", "Measures power consumption")), m_params(),
return make_unexpected(status);
}
- status = hailo_set_power_measurement(reinterpret_cast<hailo_device>(&device), 0, dvm, measurement_type);
+ status = hailo_set_power_measurement(reinterpret_cast<hailo_device>(&device), HAILO_MEASUREMENT_BUFFER_INDEX_0, dvm, measurement_type);
if (HAILO_SUCCESS != status) {
std::cerr << "Failed to set power measurement parameters, status " << status << std::endl;
return make_unexpected(status);
}
- uint32_t measurement_delay = POWER_MEASUREMENT_DELAY_MS(sampling_period, averaging_factor);
- // There is no logical way that measurement delay can be 0 - because sampling_period and averaging_factor cant be 0
- // Hence if it is 0 - it means it was 0.xx and we want to round up to 1 in that case
- if (0 == measurement_delay) {
- measurement_delay = 1;
- }
- status = hailo_start_power_measurement(reinterpret_cast<hailo_device>(&device), measurement_delay,
+ status = hailo_start_power_measurement(reinterpret_cast<hailo_device>(&device),
averaging_factor_enum, sampling_period_enum);
if (HAILO_SUCCESS != status) {
std::cerr << "Failed to start power measurement, status " << status << std::endl;
return status;
}
- status = hailo_get_power_measurement(reinterpret_cast<hailo_device>(&m_device), 0, true, &m_data);
+ status = hailo_get_power_measurement(reinterpret_cast<hailo_device>(&m_device), HAILO_MEASUREMENT_BUFFER_INDEX_0, true, &m_data);
if (HAILO_SUCCESS != status) {
std::cerr << "Failed to get power measurement results, status " << status << std::endl;
return status;
hailo_status wait_for_exit_with_timeout(std::chrono::seconds time_to_run)
{
-#if defined(__unix__)
+#if defined(__linux__)
sighandler_t prev_handler = signal(USER_SIGNAL, user_signal_handler_func);
CHECK(prev_handler != SIG_ERR, HAILO_INVALID_OPERATION, "signal failed, errno = {}", errno);
std::mutex mutex;
auto hef_new = run_subcommand->add_option("hef", params.hef_path, "An existing HEF file/directory path")
->check(CLI::ExistingFile | CLI::ExistingDirectory);
- auto hef_old = run_subcommand->add_option("--hef", params.hef_path, "An existing HEF file/directory path")
- ->check(CLI::ExistingFile | CLI::ExistingDirectory);
// Allow multiple subcommands (see https://cliutils.github.io/CLI11/book/chapters/subcommands.html)
run_subcommand->require_subcommand(0, 0);
// TODO: Support on windows (HRT-5919)
#if defined(__GNUC__)
- // TODO: Unhide (HRT-6035)
- // Unnamed "option groups" hide subcommands/options from the help message
- // (see https://github.com/CLIUtils/CLI11/blob/main/README.md)
- auto *hidden_group = run_subcommand->add_option_group("");
- auto *download_runtime_data_subcommand = hidden_group->add_subcommand("download-runtime-data",
- "Download runtime data to be used by the Profiler");
+ auto *collect_runtime_data_subcommand = run_subcommand->add_subcommand("collect-runtime-data",
+ "Collect runtime data to be used by the Profiler");
static const char *JSON_SUFFIX = ".json";
- download_runtime_data_subcommand->add_option("--output-path",
+ collect_runtime_data_subcommand->add_option("--output-path",
params.runtime_data.runtime_data_output_path, "Runtime data output file path")
- ->default_val("context_action_list.json")
+ ->default_val("runtime_data.json")
->check(FileSuffixValidator(JSON_SUFFIX));
- download_runtime_data_subcommand->parse_complete_callback([¶ms]() {
+ static const uint32_t DEFAULT_BATCH_TO_MEASURE = 2;
+ collect_runtime_data_subcommand->add_option("--batch-to-measure",
+ params.runtime_data.batch_to_measure, "Batch to be measured")
+ ->default_val(DEFAULT_BATCH_TO_MEASURE);
+ collect_runtime_data_subcommand->parse_complete_callback([¶ms]() {
// If this subcommand was parsed, then we need to download runtime_data
- params.runtime_data.download_runtime_data = true;
+ params.runtime_data.collect_runtime_data = true;
});
#endif
run_subcommand->add_flag("--measure-temp", params.measure_temp, "Measure chip temperature");
- run_subcommand->parse_complete_callback([¶ms, hef_new, hef_old, power_sampling_period,
+ run_subcommand->parse_complete_callback([¶ms, hef_new, power_sampling_period,
power_averaging_factor, measure_power_opt, measure_current_opt]() {
- PARSE_CHECK(hef_new->empty() ^ hef_old->empty(), "Single HEF file/directory is required");
+ PARSE_CHECK(!hef_new->empty(), "Single HEF file/directory is required");
bool is_hw_only = InferMode::HW_ONLY == params.mode;
params.transform.transform = (!is_hw_only || (params.inputs_name_and_file_path.size() > 0));
PARSE_CHECK((!params.transform.quantized || (HAILO_FORMAT_TYPE_AUTO == params.transform.format_type)),
!(params.power_measurement.measure_power || params.power_measurement.measure_current || params.measure_temp),
"Writing measurements in csv format is not supported for multiple devices");
+ PARSE_CHECK(("*" != params.device_params.pcie_params.pcie_bdf),
+ "Passing '*' as BDF is not supported for 'run' command. for multiple devices inference see '--device-count'");
+
if ((0 == params.time_to_run) && (0 == params.frames_count)) {
// Use default
params.time_to_run = DEFAULT_TIME_TO_RUN_SECONDS;
}
- });
- std::vector<DeprecationActionPtr> actions{
- std::make_shared<OptionDeprecation>(hef_old, "hef (positional)"),
- };
- hailo_deprecate_options(run_subcommand, actions, false);
+ if (params.runtime_data.collect_runtime_data) {
+ if ((0 != params.frames_count) && (params.frames_count < params.runtime_data.batch_to_measure)) {
+ LOGGER__WARNING("--frames-count ({}) is smaller than --batch-to-measure ({}), "
+ "hence timestamps will not be updated in runtime data", params.frames_count,
+ params.runtime_data.batch_to_measure);
+ }
+ }
+ });
}
std::map<std::string, std::string> format_strings_to_key_value_pairs(const std::vector<std::string> &key_value_pairs_str) {
auto network_group_list = device.value()->configure(hef.value(), configure_params.value());
CHECK_EXPECTED(network_group_list, "Failed configure device from hef");
+ #if defined(__GNUC__)
+ // TODO: Support on windows (HRT-5919)
+ if (params.runtime_data.collect_runtime_data) {
+ DownloadActionListCommand::set_batch_to_measure(*device.value(), params.runtime_data.batch_to_measure);
+ }
+ #endif
+
// TODO: SDK-14842, for now this function supports only one network_group
auto network_group = network_group_list.value()[0];
auto inference_result = activate_network_group_and_run(*device.value().get(), network_group, params);
#if defined(__GNUC__)
// TODO: Support on windows (HRT-5919)
- if (params.runtime_data.download_runtime_data) {
+ if (params.runtime_data.collect_runtime_data) {
+ if ((0 == params.frames_count) && inference_result) {
+ const auto frames_count = inference_result->frames_count();
+ if (frames_count && (frames_count.value() < params.runtime_data.batch_to_measure)) {
+ LOGGER__WARNING("Number of frames sent ({}) is smaller than --batch-to-measure ({}), "
+ "hence timestamps will not be updated in runtime data", frames_count.value(),
+ params.runtime_data.batch_to_measure);
+ }
+ }
+
DownloadActionListCommand::execute(*device.value(), params.runtime_data.runtime_data_output_path,
network_group_list.value(), params.hef_path);
}
#endif
-
+ CHECK_EXPECTED(inference_result);
return inference_result;
}
};
struct runtime_data_params {
- bool download_runtime_data;
+ bool collect_runtime_data;
std::string runtime_data_output_path;
+ uint16_t batch_to_measure;
};
struct inference_runner_params {
Command(parent_app.add_subcommand("scan", "Shows all available devices")),
m_device_type(Device::Type::PCIE)
{
- // TODO: `--target` and `udp` Device::TYPE::ETH are for backwards compatibility with the python implemention (`hailo`)
- // TODO: Remove them (HRT-2676)
const HailoCheckedTransformer<Device::Type> device_type_transformer({
{ "pcie", Device::Type::PCIE },
{ "eth", Device::Type::ETH },
- { "udp", Device::Type::ETH },
});
auto *device_type_option = m_app->add_option("-d,--device-type,--target", m_device_type,
- "Device type to use\n"
- "Note: 'udp' is an alias for 'eth'.")
+ "Device type to use.")
->transform(device_type_transformer)
->default_val("pcie");
// Ethernet options
auto *eth_options_group = m_app->add_option_group("Ethernet Device Options");
- // TODO: `--ip` is for backwards compatibility with the python implemention (`hailo`)
- // TODO: Remove it (HRT-2676)
auto *interface_ip_option = eth_options_group->add_option("--interface-ip", m_interface_ip_addr,
"Interface IP address to scan")
->default_val("")
->check(CLI::ValidIPV4);
- auto *ip_option = eth_options_group->add_option("--ip", m_interface_ip_addr)
- ->default_val("")
- ->excludes(interface_ip_option)
- ->check(CLI::ValidIPV4);
auto *interface_name_option = eth_options_group->add_option("--interface", m_interface_name, "Interface name to scan")
->default_val("")
- ->excludes(interface_ip_option)
- ->excludes(ip_option);
+ ->excludes(interface_ip_option);
- m_app->parse_complete_callback([this, device_type_option, interface_ip_option, ip_option, interface_name_option]() {
- bool eth_options_given = !interface_ip_option->empty() || !ip_option->empty() || !interface_name_option->empty();
+ m_app->parse_complete_callback([this, device_type_option, interface_ip_option, interface_name_option]() {
+ bool eth_options_given = !interface_ip_option->empty() || !interface_name_option->empty();
// The user didn't put target, we can figure it ourself
if (device_type_option->empty()) {
throw CLI::ParseError("Ethernet options set on non eth device", CLI::ExitCodes::InvalidError);
}
});
-
- std::vector<DeprecationActionPtr> actions{
- std::make_shared<ValueDeprecation>(device_type_option, "udp", "eth"),
- std::make_shared<OptionDeprecation>(ip_option, "--interface-ip")
- };
- hailo_deprecate_options(m_app, actions, false);
}
hailo_status ScanSubcommand::execute()
# set(CMAKE_C_CLANG_TIDY "clang-tidy;-checks=*")
set(HAILORT_MAJOR_VERSION 4)
-set(HAILORT_MINOR_VERSION 6)
+set(HAILORT_MINOR_VERSION 8)
set(HAILORT_REVISION_VERSION 0)
# Add the cmake folder so the modules there are found
if(HAILO_BUILD_PYBIND)
add_subdirectory(python)
endif()
+
# QNX currently doesnt support GStreamer
if(HAILO_BUILD_GSTREAMER AND CMAKE_HOST_UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL QNX)
add_subdirectory(gstreamer)
project(gsthailo)
+include(GNUInstallDirs)
+
if(NOT CMAKE_HOST_UNIX)
message(FATAL_ERROR "Only unix hosts are supported, stopping build")
endif()
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake/")
-find_package(HailoRT)
+find_package(HailoRT 4.8.0 EXACT REQUIRED)
# GST_PLUGIN_DEFINE needs PACKAGE to be defined
set(GST_HAILO_PACKAGE_NAME "hailo")
+++ /dev/null
-# - Try to find HailoRT
-# - If libhailort is defined (building as part of the build tree), use it
-# - Otherwise, find HAILORT_LIB and HAILORT_INCLUDE_DIR, and import libhailort
-
-if (NOT TARGET libhailort)
- # find_path finds a directory containing the named file
- find_path(HAILORT_INCLUDE_DIR "hailo/" PATH_SUFFIXES "include/")
-
- find_library(HAILORT_LIB "libhailort.so.4.6.0" PATH_SUFFIXES "lib/")
-
- include(FindPackageHandleStandardArgs)
- # Handle the QUIETLY and REQUIRED arguments and set HAILORT_FOUND to TRUE
- # if all listed variables are TRUE
- find_package_handle_standard_args(
- HailoRT
- DEFAULT_MSG
- HAILORT_LIB
- HAILORT_INCLUDE_DIR
- )
-
- add_library(HailoRT::libhailort SHARED IMPORTED)
- set_target_properties(HailoRT::libhailort PROPERTIES
- IMPORTED_LOCATION "${HAILORT_LIB}"
- INTERFACE_INCLUDE_DIRECTORIES "${HAILORT_INCLUDE_DIR}"
- )
-else()
- add_library(HailoRT::libhailort ALIAS libhailort)
-endif()
#define HAILO_SUPPORTED_FORMATS "{ RGB, YUY2 }"
#define HAILO_VIDEO_CAPS GST_VIDEO_CAPS_MAKE(HAILO_SUPPORTED_FORMATS)
+#define HAILO_DEFAULT_SCHEDULER_TIMEOUT_MS (0)
+#define HAILO_DEFAULT_SCHEDULER_THRESHOLD (1)
+
#define GST_CHECK(cond, ret_val, element, domain, ...) \
do { \
if (!(cond)) { \
2 * sampling_period (1.1) * averaging_factor (256) [ms].
Therefore we want it to be the period of time that the core will sleep between samples,
plus a factor of 20 percent */
-#define POWER_MEASUREMENT_DELAY_MS (static_cast<uint32_t>(1100 / 1000.0 * 256 * 2 * 1.2))
static void gst_hailodevicestats_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
static void gst_hailodevicestats_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
hailo_status status = m_device->stop_power_measurement();
GST_CHECK_SUCCESS(status, m_element, RESOURCE, "Stopping power measurement failed, status = %d", status);
- status = m_device->set_power_measurement(0, HAILO_DVM_OPTIONS_AUTO, HAILO_POWER_MEASUREMENT_TYPES__AUTO);
+ status = m_device->set_power_measurement(HAILO_MEASUREMENT_BUFFER_INDEX_0, HAILO_DVM_OPTIONS_AUTO, HAILO_POWER_MEASUREMENT_TYPES__AUTO);
GST_CHECK_SUCCESS(status, m_element, RESOURCE, "Setting power measurement parameters failed, status = %d", status);
- status = m_device->start_power_measurement(POWER_MEASUREMENT_DELAY_MS, HAILO_DEFAULT_INIT_AVERAGING_FACTOR, HAILO_DEFAULT_INIT_SAMPLING_PERIOD_US);
+ status = m_device->start_power_measurement(HAILO_DEFAULT_INIT_AVERAGING_FACTOR, HAILO_DEFAULT_INIT_SAMPLING_PERIOD_US);
GST_CHECK_SUCCESS(status, m_element, RESOURCE, "Starting power measurement failed, status = %d", status);
auto device_string = Device::pcie_device_info_to_string(m_device_info);
const char *device_raw_string = device_string->c_str();
while (m_is_thread_running.load()) {
- auto measurement = m_device->get_power_measurement(0, true);
+ auto measurement = m_device->get_power_measurement(HAILO_MEASUREMENT_BUFFER_INDEX_0, true);
GST_CHECK_EXPECTED_AS_STATUS(measurement, m_element, RESOURCE, "Getting power measurement failed, status = %d", measurement.status());
if (!m_is_silent) {
GST_DEBUG_CATEGORY_STATIC(gst_hailonet_debug_category);
#define GST_CAT_DEFAULT gst_hailonet_debug_category
+#define GST_TYPE_SCHEDULING_ALGORITHM (gst_scheduling_algorithm_get_type ())
+static GType
+gst_scheduling_algorithm_get_type (void)
+{
+ static GType scheduling_algorithm_type = 0;
+
+ /* Tightly coupled to hailo_scheduling_algorithm_e */
+
+ if (!scheduling_algorithm_type) {
+ static GEnumValue algorithm_types[] = {
+ { HAILO_SCHEDULING_ALGORITHM_NONE, "Scheduler is not active", "HAILO_SCHEDULING_ALGORITHM_NONE" },
+ { HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN, "Round robin", "HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN" },
+ { HAILO_SCHEDULING_ALGORITHM_MAX_ENUM, NULL, NULL },
+ };
+
+ scheduling_algorithm_type =
+ g_enum_register_static ("GstHailoSchedulingAlgorithms", algorithm_types);
+ }
+
+ return scheduling_algorithm_type;
+}
+
constexpr std::chrono::milliseconds WAIT_FOR_FLUSH_TIMEOUT_MS(1000);
static void gst_hailonet_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
PROP_OUTPUTS_MAX_POOL_SIZE,
PROP_IS_ACTIVE,
PROP_DEVICE_COUNT,
- PROP_VDEVICE_KEY
+ PROP_VDEVICE_KEY,
+ PROP_SCHEDULING_ALGORITHM,
+ PROP_SCHEDULER_TIMEOUT_MS,
+ PROP_SCHEDULER_THRESHOLD,
};
G_DEFINE_TYPE(GstHailoNet, gst_hailonet, GST_TYPE_BIN);
DEFAULT_OUTPUTS_MAX_POOL_SIZE, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property(gobject_class, PROP_IS_ACTIVE,
g_param_spec_boolean("is-active", "Is Network Activated", "Controls whether this element should be active. "
- "By default, the hailonet element will not be active unless there is only one hailonet in the pipeline", false,
+ "By default, the hailonet element will not be active unless it is the only one. "
+ "Setting this property in combination with 'scheduling-algorithm' different than HAILO_SCHEDULING_ALGORITHM_NONE is not supported.", false,
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property(gobject_class, PROP_SCHEDULING_ALGORITHM,
+ g_param_spec_enum("scheduling-algorithm", "Scheduling policy for automatic network group switching", "Controls the Model Scheduler algorithm of HailoRT. "
+ "Gets values from the enum GstHailoSchedulingAlgorithms. "
+ "Using Model Scheduler algorithm different than HAILO_SCHEDULING_ALGORITHM_NONE, excludes the property 'is-active'. "
+ "When using the same VDevice across multiple hailonets, all should have the same 'scheduling-algorithm'. "
+ "Currently only supported with 1 device (e.g. device-count=1).",
+ GST_TYPE_SCHEDULING_ALGORITHM, HAILO_SCHEDULING_ALGORITHM_NONE,
+ (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property(gobject_class, PROP_SCHEDULER_TIMEOUT_MS,
+ g_param_spec_uint("scheduler-timeout-ms", "Timeout for for scheduler in ms", "The maximum time period that may pass before getting run time from the scheduler,"
+ " as long as at least one send request has been sent.",
+ HAILO_DEFAULT_SCHEDULER_TIMEOUT_MS, std::numeric_limits<uint32_t>::max(), HAILO_DEFAULT_SCHEDULER_TIMEOUT_MS, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property(gobject_class, PROP_SCHEDULER_THRESHOLD,
+ g_param_spec_uint("scheduler-threshold", "Frames threshold for scheduler", "The minimum number of send requests required before the hailonet is considered ready to get run time from the scheduler.",
+ HAILO_DEFAULT_SCHEDULER_THRESHOLD, std::numeric_limits<uint32_t>::max(), HAILO_DEFAULT_SCHEDULER_THRESHOLD, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
// See information about the "flush" signal in the element description
g_signal_new(
"flush",
{
gboolean new_is_active = g_value_get_boolean(value);
+ if (HAILO_SCHEDULING_ALGORITHM_NONE != m_props.m_scheduling_algorithm.get()) {
+ g_error("scheduling-algorithm different than HAILO_SCHEDULING_ALGORITHM_NONE in combination with 'is-active' is not supported.");
+ break;
+ }
+
if (m_has_called_activate) {
if (m_props.m_is_active.get() && !new_is_active) {
// Setting this to false before deactivating to signal hailosend and hailorecv to stop inferring
}
break;
}
+ case PROP_SCHEDULING_ALGORITHM:
+ if (m_was_configured) {
+ g_warning("The network was already configured so changing the scheduling algorithm will not take place!");
+ break;
+ }
+ if (m_props.m_is_active.was_changed() && (g_value_get_enum(value) != HAILO_SCHEDULING_ALGORITHM_NONE)) {
+ g_error("scheduling-algorithm different than HAILO_SCHEDULING_ALGORITHM_NONE in combination with 'is-active' is not supported.");
+ break;
+ }
+ m_props.m_scheduling_algorithm = static_cast<hailo_scheduling_algorithm_t>(g_value_get_enum(value));
+ break;
+ case PROP_SCHEDULER_TIMEOUT_MS:
+ if (m_was_configured) {
+ g_warning("The network was already configured so changing the scheduling algorithm will not take place!");
+ break;
+ }
+ if (m_props.m_is_active.was_changed()) {
+ g_error("scheduler usage (scheduler-timeout-ms) in combination with 'is-active' is not supported.");
+ break;
+ }
+ m_props.m_scheduler_timeout_ms = g_value_get_uint(value);
+ break;
+ case PROP_SCHEDULER_THRESHOLD:
+ if (m_was_configured) {
+ g_warning("The network was already configured so changing the scheduling algorithm will not take place!");
+ break;
+ }
+ if (m_props.m_is_active.was_changed()) {
+ g_error("scheduler usage (scheduler-threshold) in combination with 'is-active' is not supported.");
+ break;
+ }
+ m_props.m_scheduler_threshold = g_value_get_uint(value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
case PROP_IS_ACTIVE:
g_value_set_boolean(value, m_props.m_is_active.get());
break;
+ case PROP_SCHEDULING_ALGORITHM:
+ g_value_set_enum(value, m_props.m_scheduling_algorithm.get());
+ break;
+ case PROP_SCHEDULER_TIMEOUT_MS:
+ g_value_set_uint(value, m_props.m_scheduler_timeout_ms.get());
+ break;
+ case PROP_SCHEDULER_THRESHOLD:
+ g_value_set_uint(value, m_props.m_scheduler_threshold.get());
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
GST_CHECK(nullptr != m_net_group_handle, HAILO_OUT_OF_HOST_MEMORY, m_element, RESOURCE, "Failed allocating memory for network handle!");
hailo_status status = m_net_group_handle->set_hef(m_props.m_device_id.get(), m_props.m_device_count.get(), m_props.m_vdevice_key.get(),
- m_props.m_hef_path.get());
+ m_props.m_scheduling_algorithm.get(), m_props.m_hef_path.get());
if (HAILO_SUCCESS != status) {
return status;
}
}
m_was_configured = true;
+ if (m_props.m_scheduler_timeout_ms.was_changed()) {
+ status = m_net_group_handle->set_scheduler_timeout(m_props.m_network_name.get(), m_props.m_scheduler_timeout_ms.get());
+ GST_CHECK_SUCCESS(status, m_element, RESOURCE, "Setting scheduler timeout failed, status = %d", status);
+ }
+ if (m_props.m_scheduler_threshold.was_changed()) {
+ status = m_net_group_handle->set_scheduler_threshold(m_props.m_network_name.get(), m_props.m_scheduler_threshold.get());
+ GST_CHECK_SUCCESS(status, m_element, RESOURCE, "Setting scheduler threshold failed, status = %d", status);
+ }
+
auto vstreams = m_net_group_handle->create_vstreams(m_props.m_network_name.get(), m_output_formats);
GST_CHECK_EXPECTED_AS_STATUS(vstreams, m_element, RESOURCE, "Creating vstreams failed, status = %d", status);
return HAILO_SUCCESS;
}
-hailo_status HailoNetImpl::activate_network_group()
+hailo_status HailoNetImpl::activate_hailonet()
{
+ if (HAILO_SCHEDULING_ALGORITHM_NONE != m_props.m_scheduling_algorithm.get()) {
+ m_props.m_is_active = true;
+ return HAILO_SUCCESS;
+ }
+
if ((1 == m_hailonet_count) && (!m_props.m_is_active.was_changed())) {
m_props.m_is_active = true;
}
GST_CHECK_EXPECTED_AS_STATUS(was_deactivated, m_element, RESOURCE, "Failed removing network, status = %d", was_deactivated.status());
if (was_deactivated.value()) {
- if (nullptr != GST_HAILOSEND(m_hailosend)->impl) {
- hailo_status status = GST_HAILOSEND(m_hailosend)->impl->clear_vstreams();
- GST_CHECK_SUCCESS(status, m_element, RESOURCE, "Failed clearing input VStreams of hailosend, status = %d", status);
- }
+ return clear_vstreams();
+ }
+ return HAILO_SUCCESS;
+}
- if (nullptr != GST_HAILORECV(m_hailorecv)->impl) {
- hailo_status status = GST_HAILORECV(m_hailorecv)->impl->clear_vstreams();
- GST_CHECK_SUCCESS(status, m_element, RESOURCE, "Failed clearing output VStreams of hailorecv, status = %d", status);
- }
+hailo_status HailoNetImpl::clear_vstreams()
+{
+ if (nullptr != GST_HAILOSEND(m_hailosend)->impl) {
+ hailo_status status = GST_HAILOSEND(m_hailosend)->impl->clear_vstreams();
+ GST_CHECK_SUCCESS(status, m_element, RESOURCE, "Failed clearing input VStreams of hailosend, status = %d", status);
+ }
+
+ if (nullptr != GST_HAILORECV(m_hailorecv)->impl) {
+ hailo_status status = GST_HAILORECV(m_hailorecv)->impl->clear_vstreams();
+ GST_CHECK_SUCCESS(status, m_element, RESOURCE, "Failed clearing output VStreams of hailorecv, status = %d", status);
}
return HAILO_SUCCESS;
GstPadProbeReturn HailoNetImpl::sink_probe()
{
- hailo_status status = activate_network_group();
+ hailo_status status = activate_hailonet();
GST_CHECK(HAILO_SUCCESS == status, GST_PAD_PROBE_REMOVE, m_element, RESOURCE, "Failed activating network, status = %d", status);
return GST_PAD_PROBE_REMOVE;
}
return m_was_flushed_event->signal();
}
+static bool do_versions_match(GstHailoNet *self)
+{
+ hailo_version_t libhailort_version = {};
+ auto status = hailo_get_library_version(&libhailort_version);
+ if (HAILO_SUCCESS != status) {
+ GST_ELEMENT_ERROR(self, RESOURCE, FAILED, ("Fetching libhailort version has failed! status = %d", status), (NULL));
+ return false;
+ }
+
+ bool versions_match = ((HAILORT_MAJOR_VERSION == libhailort_version.major) &&
+ (HAILORT_MINOR_VERSION == libhailort_version.minor) &&
+ (HAILORT_REVISION_VERSION == libhailort_version.revision));
+ if (!versions_match) {
+ GST_ELEMENT_ERROR(self, RESOURCE, FAILED, ("libhailort version (%d.%d.%d) does not match gsthailonet version (%d.%d.%d)",
+ libhailort_version.major, libhailort_version.minor, libhailort_version.revision,
+ HAILORT_MAJOR_VERSION, HAILORT_MINOR_VERSION, HAILORT_REVISION_VERSION), (NULL));
+ return false;
+ }
+ return true;
+}
+
static void gst_hailonet_init(GstHailoNet *self)
{
+ if (!do_versions_match(self)) {
+ return;
+ }
+
auto hailonet_impl = HailoNetImpl::create(self);
if (!hailonet_impl) {
GST_ELEMENT_ERROR(self, RESOURCE, FAILED, ("Creating hailonet implementation has failed! status = %d", hailonet_impl.status()), (NULL));
}
case GST_STATE_CHANGE_READY_TO_NULL:
{
+ // VStreams are destructed in hailosend's/hailorecv's GST_STATE_CHANGE_READY_TO_NULL (which calls 'clear_abort' on low-level streams)
// We abort streams again because deactivation of the activated network group calls flush, and it can fail on timeout unless we call abort
hailo_status status = hailonet->abort_streams();
GST_CHECK(HAILO_SUCCESS == status, GST_STATE_CHANGE_FAILURE, element, RESOURCE, "Aborting streams has failed, status = %d\n", status);
- status = hailonet->deactivate_network_group();
- GST_CHECK(HAILO_SUCCESS == status, GST_STATE_CHANGE_FAILURE, element, RESOURCE, "Deactivating network group has failed, status = %d\n", status);
+ if (HAILO_SCHEDULING_ALGORITHM_NONE == hailonet->get_props().m_scheduling_algorithm.get()) {
+ status = hailonet->deactivate_network_group();
+ GST_CHECK(HAILO_SUCCESS == status, GST_STATE_CHANGE_FAILURE, element, RESOURCE, "Deactivating network group failed, status = %d\n", status);
+ }
// Cleanup all of hailonet memory
hailonet.reset();
{
public:
HailoNetProperties() : m_device_id(nullptr), m_hef_path(nullptr), m_network_name(nullptr), m_batch_size(HAILO_DEFAULT_BATCH_SIZE),
- m_is_active(false), m_device_count(0), m_vdevice_key(DEFAULT_VDEVICE_KEY)
+ m_is_active(false), m_device_count(0), m_vdevice_key(DEFAULT_VDEVICE_KEY), m_scheduling_algorithm(HAILO_SCHEDULING_ALGORITHM_NONE),
+ m_scheduler_timeout_ms(HAILO_DEFAULT_SCHEDULER_TIMEOUT_MS), m_scheduler_threshold(HAILO_DEFAULT_SCHEDULER_THRESHOLD)
{}
HailoElemProperty<gchar*> m_device_id;
HailoElemProperty<gboolean> m_is_active;
HailoElemProperty<guint16> m_device_count;
HailoElemProperty<guint32> m_vdevice_key;
+ HailoElemProperty<hailo_scheduling_algorithm_t> m_scheduling_algorithm;
+ HailoElemProperty<guint32> m_scheduler_timeout_ms;
+ HailoElemProperty<guint32> m_scheduler_threshold;
};
class HailoNetImpl final
hailo_status set_hef();
hailo_status link_elements();
hailo_status configure_network_group();
- hailo_status activate_network_group();
+ hailo_status activate_hailonet();
hailo_status abort_streams();
- hailo_status deactivate_network_group();
+
gboolean src_pad_event(GstEvent *event);
GstPadProbeReturn sink_probe();
gboolean is_active();
hailo_status flush();
hailo_status signal_was_flushed_event();
+ hailo_status deactivate_network_group();
+ HailoNetProperties &get_props() {
+ return m_props;
+ }
+
private:
void init_ghost_sink();
void init_ghost_src();
Expected<std::string> get_network_group_name(const std::string &network_name);
+ hailo_status clear_vstreams();
+
static std::atomic_uint32_t m_hailonet_count;
static std::mutex m_mutex;
GstHailoNet *m_element;
++hailo_pool->buffers_acquired;
GstStructure *pool_config = gst_buffer_pool_get_config(pool);
- GstCaps *caps = nullptr;
- guint size = 0;
- guint min_buffers = 0;
guint max_buffers = 0;
- gboolean result = gst_buffer_pool_config_get_params(pool_config, &caps, &size, &min_buffers, &max_buffers);
+ gboolean result = gst_buffer_pool_config_get_params(pool_config, NULL, NULL, NULL, &max_buffers);
+ gst_structure_free(pool_config);
if (!result) {
g_error("Failed getting config params from buffer pool!");
return GST_FLOW_ERROR;
GType gst_hailo_buffer_flag_meta_api_get_type(void)
{
- static volatile GType type;
+ // https://github.com/vmware/open-vm-tools/commit/b2c8baeaa8ac365e1445f941cf1b80999ed89a9d
+ static GType type;
static const gchar *tags[] = {HAILO_BUFFER_FLAG_META_TAG, NULL};
if (g_once_init_enter(&type)) {
GType gst_tensor_meta_api_get_type(void)
{
- static volatile GType type;
+ // https://github.com/vmware/open-vm-tools/commit/b2c8baeaa8ac365e1445f941cf1b80999ed89a9d
+ static GType type;
static const gchar *tags[] = {TENSOR_META_TAG, NULL};
if (g_once_init_enter(&type)) {
NetworkGroupConfigManager NetworkGroupHandle::m_net_group_config_manager;
NetworkGroupActivationManager NetworkGroupHandle::m_net_group_activation_manager;
-Expected<std::shared_ptr<VDevice>> NetworkGroupHandle::create_vdevice(const std::string &device_id, uint16_t device_count, uint32_t vdevice_key)
+Expected<std::shared_ptr<VDevice>> NetworkGroupHandle::create_vdevice(const std::string &device_id, uint16_t device_count, uint32_t vdevice_key,
+ hailo_scheduling_algorithm_t scheduling_algorithm)
{
- auto expected_device = m_vdevice_manager.create_vdevice(m_element, device_id, device_count, vdevice_key);
+ auto expected_device = m_vdevice_manager.create_vdevice(m_element, device_id, device_count, vdevice_key, scheduling_algorithm);
GST_CHECK_EXPECTED(expected_device, m_element, RESOURCE, "Failed creating vdevice, status = %d", expected_device.status());
return expected_device;
}
-hailo_status NetworkGroupHandle::set_hef(const char *device_id, uint16_t device_count, uint32_t vdevice_key, const char *hef_path)
+hailo_status NetworkGroupHandle::set_hef(const char *device_id, uint16_t device_count, uint32_t vdevice_key,
+ hailo_scheduling_algorithm_t scheduling_algorithm, const char *hef_path)
{
if (0 == device_count) {
device_count = HAILO_DEFAULT_DEVICE_COUNT;
std::string device_id_str = (nullptr == device_id) ? "" : device_id;
- auto vdevice = create_vdevice(device_id_str, device_count, vdevice_key);
+ auto vdevice = create_vdevice(device_id_str, device_count, vdevice_key, scheduling_algorithm);
GST_CHECK_EXPECTED_AS_STATUS(vdevice, m_element, RESOURCE, "Failed creating vdevice, status = %d", vdevice.status());
m_vdevice = vdevice.release();
return HAILO_SUCCESS;
}
+
+hailo_status NetworkGroupHandle::set_scheduler_timeout(const char *network_name, uint32_t timeout_ms)
+{
+ return m_cng->set_scheduler_timeout(std::chrono::milliseconds(timeout_ms), network_name);
+}
+
+hailo_status NetworkGroupHandle::set_scheduler_threshold(const char *network_name, uint32_t threshold)
+{
+ return m_cng->set_scheduler_threshold(threshold, network_name);
+}
+
Expected<std::pair<std::vector<InputVStream>, std::vector<OutputVStream>>> NetworkGroupHandle::create_vstreams(const char *network_name,
const std::vector<hailo_format_with_name_t> &output_formats)
{
GST_CHECK(nullptr != network_name, make_unexpected(HAILO_INVALID_ARGUMENT), m_element, RESOURCE, "Got nullptr in network name!");
m_network_name = network_name;
- hailo_status status = m_net_group_config_manager.add_network(m_network_name, m_element);
+ hailo_status status = m_net_group_config_manager.add_network_to_shared_network_group(m_shared_device_id, m_network_name, m_element);
GST_CHECK(HAILO_SUCCESS == status, make_unexpected(status), m_element, RESOURCE,
"Inserting network name to configured networks has failed, status = %d", status);
Expected<std::shared_ptr<VDevice>> VDeviceManager::create_vdevice(const void *element, const std::string &device_id, uint16_t device_count,
- uint32_t vdevice_key)
+ uint32_t vdevice_key, hailo_scheduling_algorithm_t scheduling_algorithm)
{
std::unique_lock<std::mutex> lock(m_mutex);
if (!device_id.empty()) {
- return create_shared_vdevice(element, device_id);
+ return create_shared_vdevice(element, device_id, scheduling_algorithm);
}
if (DEFAULT_VDEVICE_KEY != vdevice_key) {
- return create_shared_vdevice(element, device_count, vdevice_key);
+ return create_shared_vdevice(element, device_count, vdevice_key, scheduling_algorithm);
}
- return create_unique_vdevice(element, device_count);
+ return create_unique_vdevice(element, device_count, scheduling_algorithm);
}
-Expected<std::shared_ptr<VDevice>> VDeviceManager::create_shared_vdevice(const void *element, const std::string &device_id)
+Expected<std::shared_ptr<VDevice>> VDeviceManager::create_shared_vdevice(const void *element, const std::string &device_id,
+ hailo_scheduling_algorithm_t scheduling_algorithm)
{
// If passing device_id, than device_count must be 1
const auto device_count = 1;
// If vdevice already exist, use it
- auto found_vdevice = get_vdevice(device_id);
- if (found_vdevice) {
+ auto found_vdevice = get_vdevice(device_id, scheduling_algorithm);
+ if (found_vdevice.status() != HAILO_NOT_FOUND) {
+ GST_CHECK_EXPECTED(found_vdevice, element, RESOURCE, "Failed using shared vdevice, status = %d", found_vdevice.status());
return found_vdevice.release();
}
hailo_vdevice_params_t params = {};
params.device_count = device_count;
params.device_infos = &(device_info_expected.value());
+ params.scheduling_algorithm = scheduling_algorithm;
auto vdevice = VDevice::create(params);
GST_CHECK_EXPECTED(vdevice, element, RESOURCE, "Failed creating vdevice, status = %d", vdevice.status());
std::shared_ptr<VDevice> vdevice_ptr = std::move(vdevice.release());
m_shared_vdevices[device_id] = vdevice_ptr;
+ m_shared_vdevices_scheduling_algorithm[device_id] = scheduling_algorithm;
return vdevice_ptr;
}
-Expected<std::shared_ptr<VDevice>> VDeviceManager::create_shared_vdevice(const void *element, uint16_t device_count, uint32_t vdevice_key)
+Expected<std::shared_ptr<VDevice>> VDeviceManager::create_shared_vdevice(const void *element, uint16_t device_count, uint32_t vdevice_key,
+ hailo_scheduling_algorithm_t scheduling_algorithm)
{
auto device_id = std::to_string(device_count) + "-" + std::to_string(vdevice_key);
// If vdevice already exist, use it
- auto found_vdevice = get_vdevice(device_id);
- if (found_vdevice) {
+ auto found_vdevice = get_vdevice(device_id, scheduling_algorithm);
+ if (found_vdevice.status() != HAILO_NOT_FOUND) {
+ GST_CHECK_EXPECTED(found_vdevice, element, RESOURCE, "Failed using shared vdevice, status = %d", found_vdevice.status());
return found_vdevice.release();
}
hailo_vdevice_params_t params = {};
params.device_count = device_count;
params.device_infos = nullptr;
+ params.scheduling_algorithm = scheduling_algorithm;
auto vdevice = VDevice::create(params);
GST_CHECK_EXPECTED(vdevice, element, RESOURCE, "Failed creating vdevice, status = %d", vdevice.status());
std::shared_ptr<VDevice> vdevice_ptr = std::move(vdevice.release());
m_shared_vdevices[device_id] = vdevice_ptr;
+ m_shared_vdevices_scheduling_algorithm[device_id] = scheduling_algorithm;
return vdevice_ptr;
}
-Expected<std::shared_ptr<VDevice>> VDeviceManager::create_unique_vdevice(const void *element, uint16_t device_count)
+Expected<std::shared_ptr<VDevice>> VDeviceManager::create_unique_vdevice(const void *element, uint16_t device_count,
+ hailo_scheduling_algorithm_t scheduling_algorithm)
{
hailo_vdevice_params_t params = {};
params.device_count = device_count;
params.device_infos = nullptr;
+ params.scheduling_algorithm = scheduling_algorithm;
auto vdevice = VDevice::create(params);
GST_CHECK_EXPECTED(vdevice, element, RESOURCE, "Failed creating vdevice, status = %d", vdevice.status());
return vdevice_ptr;
}
-Expected<std::shared_ptr<VDevice>> VDeviceManager::get_vdevice(const std::string &device_id)
+Expected<std::shared_ptr<VDevice>> VDeviceManager::get_vdevice(const std::string &device_id,
+ hailo_scheduling_algorithm_t scheduling_algorithm)
{
auto found = m_shared_vdevices.find(device_id);
if (found == m_shared_vdevices.end()) {
return make_unexpected(HAILO_NOT_FOUND);
}
+
+ // shared_vdevice is found, verify the requested scheduling_algorithm
+ assert(m_shared_vdevices_scheduling_algorithm.end() != m_shared_vdevices_scheduling_algorithm.find(device_id));
+ if (scheduling_algorithm != m_shared_vdevices_scheduling_algorithm[device_id]) {
+ auto status = HAILO_INVALID_OPERATION;
+ g_warning("Shared vdevice with the same credentials is already exists (%s) but with a different scheduling-algorithm (requested: %d, exists: %d), status = %d",
+ device_id.c_str(), scheduling_algorithm, m_shared_vdevices_scheduling_algorithm[device_id], status);
+ return make_unexpected(HAILO_INVALID_OPERATION);
+ }
+
auto vdevice_cpy = found->second;
return vdevice_cpy;
}
return std::move(network_group_list->at(0));
}
-hailo_status NetworkGroupConfigManager::add_network(const std::string &network_name, const GstElement *owner_element)
+hailo_status NetworkGroupConfigManager::add_network_to_shared_network_group(const std::string &shared_device_id, const std::string &network_name,
+ const GstElement *owner_element)
{
std::unique_lock<std::mutex> lock(m_mutex);
- auto found = m_configured_networks.find(network_name);
- GST_CHECK(found == m_configured_networks.end(), HAILO_INVALID_OPERATION, owner_element, RESOURCE,
- "Network %s was already configured by %s!", network_name.c_str(), found->second.c_str());
+ if (shared_device_id.empty()) {
+ // the device is unique so we don't need to share anything
+ return HAILO_SUCCESS;
+ }
+
+ auto found_by_device = m_configured_networks.find(shared_device_id);
+ if (found_by_device != m_configured_networks.end()) {
+ auto found_network = found_by_device->second.find(network_name);
+ GST_CHECK(found_network == found_by_device->second.end(), HAILO_INVALID_OPERATION, owner_element, RESOURCE,
+ "Network %s was already configured by %s by the same device!", network_name.c_str(), found_network->second.c_str());
+ }
- m_configured_networks[network_name] = GST_ELEMENT_NAME(owner_element);
+ m_configured_networks[shared_device_id][network_name] = GST_ELEMENT_NAME(owner_element);
return HAILO_SUCCESS;
}
class VDeviceManager final
{
public:
- VDeviceManager() : m_shared_vdevices(), m_unique_vdevices() {}
+ VDeviceManager() : m_shared_vdevices(), m_shared_vdevices_scheduling_algorithm(), m_unique_vdevices() {}
- Expected<std::shared_ptr<VDevice>> create_vdevice(const void *element, const std::string &device_id, uint16_t device_count, uint32_t vdevice_key);
+ Expected<std::shared_ptr<VDevice>> create_vdevice(const void *element, const std::string &device_id, uint16_t device_count, uint32_t vdevice_key,
+ hailo_scheduling_algorithm_t scheduling_algorithm);
private:
- Expected<std::shared_ptr<VDevice>> create_shared_vdevice(const void *element, const std::string &device_id);
- Expected<std::shared_ptr<VDevice>> create_shared_vdevice(const void *element, uint16_t device_count, uint32_t vdevice_key);
- Expected<std::shared_ptr<VDevice>> create_unique_vdevice(const void *element, uint16_t device_count);
- Expected<std::shared_ptr<VDevice>> get_vdevice(const std::string &device_id);
+ Expected<std::shared_ptr<VDevice>> create_shared_vdevice(const void *element, const std::string &device_id,
+ hailo_scheduling_algorithm_t scheduling_algorithm);
+ Expected<std::shared_ptr<VDevice>> create_shared_vdevice(const void *element, uint16_t device_count, uint32_t vdevice_key,
+ hailo_scheduling_algorithm_t scheduling_algorithm);
+ Expected<std::shared_ptr<VDevice>> create_unique_vdevice(const void *element, uint16_t device_count,
+ hailo_scheduling_algorithm_t scheduling_algorithm);
+ Expected<std::shared_ptr<VDevice>> get_vdevice(const std::string &device_id, hailo_scheduling_algorithm_t scheduling_algorithm);
/* Contains only the shared vdevices (either created by bdf, or with device-count && vdevice-key)
Keys are either "<BDF>" or "<device_count>-<vdevice_key>" */
std::unordered_map<std::string, std::shared_ptr<VDevice>> m_shared_vdevices;
+ std::unordered_map<std::string, hailo_scheduling_algorithm_t> m_shared_vdevices_scheduling_algorithm; // Used to check that 2 shared vdevices gets the same scheduling-algorithm
std::vector<std::shared_ptr<VDevice>> m_unique_vdevices;
std::mutex m_mutex;
};
+using device_id_t = std::string;
using network_name_t = std::string;
using hailonet_name_t = std::string;
Expected<std::shared_ptr<ConfiguredNetworkGroup>> configure_network_group(const void *element, const std::string &device_id,
const char *network_group_name, uint16_t batch_size, std::shared_ptr<VDevice> &vdevice, std::shared_ptr<Hef> hef,
NetworkGroupsParamsMap &net_groups_params_map);
- hailo_status add_network(const std::string &network_name, const GstElement *owner_element);
+ hailo_status add_network_to_shared_network_group(const std::string &shared_device_id, const std::string &network_name,
+ const GstElement *owner_element);
private:
static std::string get_configure_string(const std::string &device_id, const char *network_group_name, uint16_t batch_size);
// TODO: change this map to store only the shared network_groups (used by multiple hailonets with the same vdevices)
std::unordered_map<std::string, std::shared_ptr<ConfiguredNetworkGroup>> m_configured_net_groups;
- std::unordered_map<network_name_t, hailonet_name_t> m_configured_networks;
+ std::unordered_map<device_id_t, std::unordered_map<network_name_t, hailonet_name_t>> m_configured_networks;
std::mutex m_mutex;
};
NetworkGroupHandle(const GstElement *element) : m_element(element), m_shared_device_id(), m_net_group_name(), m_network_name(), m_batch_size(0),
m_vdevice(nullptr), m_hef(nullptr), m_cng(nullptr), m_ang(nullptr) {}
- hailo_status set_hef(const char *device_id, uint16_t device_count, uint32_t vdevice_key, const char *hef_path);
+ hailo_status set_hef(const char *device_id, uint16_t device_count, uint32_t vdevice_key, hailo_scheduling_algorithm_t scheduling_algorithm,
+ const char *hef_path);
hailo_status configure_network_group(const char *net_group_name, uint16_t batch_size);
Expected<std::pair<std::vector<InputVStream>, std::vector<OutputVStream>>> create_vstreams(const char *network_name,
const std::vector<hailo_format_with_name_t> &output_formats);
hailo_status abort_streams();
Expected<bool> remove_network_group();
+ hailo_status set_scheduler_timeout(const char *network_name, uint32_t timeout_ms);
+ hailo_status set_scheduler_threshold(const char *network_name, uint32_t threshold);
+
+
std::shared_ptr<Hef> hef()
{
return m_hef;
private:
Expected<NetworkGroupsParamsMap> get_configure_params(Hef &hef, const char *net_group_name, uint16_t batch_size);
- Expected<std::shared_ptr<VDevice>> create_vdevice(const std::string &device_id, uint16_t device_count, uint32_t vdevice_key);
+ Expected<std::shared_ptr<VDevice>> create_vdevice(const std::string &device_id, uint16_t device_count, uint32_t vdevice_key,
+ hailo_scheduling_algorithm_t scheduling_algorithm);
static VDeviceManager m_vdevice_manager;
static NetworkGroupConfigManager m_net_group_config_manager;
static NetworkGroupActivationManager m_net_group_activation_manager;
const GstElement *m_element;
- std::string m_shared_device_id;
+ std::string m_shared_device_id; // empty string when using unique device
std::string m_net_group_name;
std::string m_network_name;
uint16_t m_batch_size;
add_subdirectory(src)
+
+# copy files to venv
+if(HAILO_BUILD_PYHAILORT_VENV)
+ add_custom_target(pyhailort_venv ALL
+ COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:_pyhailort> ${CMAKE_CURRENT_LIST_DIR}/platform/hailo_platform/pyhailort/
+ )
+ add_dependencies(pyhailort_venv _pyhailort)
+endif()
\ No newline at end of file
from hailo_platform import (HEF, PcieDevice, ConfigureParams, InferVStreams, InputVStreamParams,
OutputVStreamParams, FormatType)
-from hailo_platform.drivers.hailort.pyhailort import HailoStreamInterface
+from hailo_platform.pyhailort.pyhailort import HailoStreamInterface
import numpy as np
import argparse
input_data = {name : 1 + np.ndarray([args.num_frames] + list(shape), dtype=np.float32) for name, shape in input_names_to_shape.items()}
with network_group.activate(network_group_params):
_ = infer_pipeline.infer(input_data)
+
+ print('Inference ran successfully')
if __name__ == '__main__':
main()
\ No newline at end of file
import pathlib
import pprint
-from hailo_platform.common.paths_manager.version import get_version
-from hailo_platform.common.paths_manager.paths import PackingInfo, PackingStatus
-
class MissingPyHRTLib(Exception):
pass
-# This hack checks which modules the user has on his computer.
-# packing status set to "packed_client" if it can't import the PLATFORM_INTERNALS module
-# it set the packing status to "standalone_platform" if it can't import the SDK_COMMON module
-
-try:
- import hailo_platform_internals # noqa F401
-except ImportError:
- PackingInfo().status = PackingStatus.packed_client
-
-try:
- import hailo_sdk_common # noqa F401
-except:
- PackingInfo().status = PackingStatus.standalone_platform
-
-
-
-# This hack only affects internals users with hailo_validation installed.
-# It changes the packing status to PACKED if it thinks SDK was installed from
-# wheel.
-try:
- import hailo_validation # noqa F401
- if 'site-packages/hailo_sdk' in __path__[0] :
- PackingInfo().status = PackingStatus.packed_client
-except ImportError:
- pass
-
-
# Must appear before other imports:
def join_drivers_path(path):
_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
from hailo_platform.tools.udp_rate_limiter import UDPRateLimiter
-from hailo_platform.drivers.hw_object import PcieDevice, EthernetDevice
-from hailo_platform.drivers.hailo_controller.power_measurement import (DvmTypes,
- PowerMeasurementTypes,
- SamplingPeriod, AveragingFactor)
-from hailo_platform.drivers.hailort.pyhailort import (HEF, ConfigureParams,
+from hailo_platform.pyhailort.hw_object import PcieDevice, EthernetDevice
+from hailo_platform.pyhailort.pyhailort import (HEF, ConfigureParams,
FormatType, FormatOrder,
MipiDataTypeRx, MipiPixelsPerClock,
MipiClockSelection, MipiIspImageInOrder,
Endianness, HailoStreamInterface,
InputVStreamParams, OutputVStreamParams,
InputVStreams, OutputVStreams,
- InferVStreams, HailoStreamDirection, HailoFormatFlags, HailoCpuId, VDevice)
+ InferVStreams, HailoStreamDirection, HailoFormatFlags, HailoCpuId, VDevice,
+ DvmTypes, PowerMeasurementTypes, SamplingPeriod, AveragingFactor, MeasurementBufferIndex)
def _verify_pyhailort_lib_exists():
python_version = "".join(str(i) for i in sys.version_info[:2])
"nt": "pyd", # Windows
}[os.name]
- path = f"{__path__[0]}/drivers/hailort/"
+ path = f"{__path__[0]}/pyhailort/"
if next(pathlib.Path(path).glob(f"_pyhailort*.{lib_extension}"), None) is None:
raise MissingPyHRTLib(f"{path} should include a _pyhailort library (_pyhailort*{python_version}*.{lib_extension}). Includes: {pprint.pformat(list(pathlib.Path(path).iterdir()))}")
_verify_pyhailort_lib_exists()
+def get_version(package_name):
+ # See: https://packaging.python.org/guides/single-sourcing-package-version/ (Option 5)
+ # We assume that the installed package is actually the same one we import. This assumption may
+ # break in some edge cases e.g. if the user modifies sys.path manually.
+
+ # hailo_platform package has been renamed to hailort, but the import is still hailo_platform
+ if package_name == "hailo_platform":
+ package_name = "hailort"
+ try:
+ import pkg_resources
+ return pkg_resources.get_distribution(package_name).version
+ except:
+ return 'unknown'
__version__ = get_version('hailo_platform')
__all__ = ['EthernetDevice', 'DvmTypes', 'PowerMeasurementTypes',
- 'SamplingPeriod', 'AveragingFactor', 'UDPRateLimiter', 'PcieDevice', 'HEF',
+ 'SamplingPeriod', 'AveragingFactor', 'MeasurementBufferIndex', 'UDPRateLimiter', 'PcieDevice', 'HEF',
'ConfigureParams', 'FormatType', 'FormatOrder', 'MipiDataTypeRx', 'MipiPixelsPerClock', 'MipiClockSelection',
'MipiIspImageInOrder', 'MipiIspImageOutDataType', 'join_drivers_path', 'IspLightFrequency', 'HailoPowerMode',
'Endianness', 'HailoStreamInterface', 'InputVStreamParams', 'OutputVStreamParams',
+++ /dev/null
-#!/usr/bin/env python
-import six
-from io import IOBase
-
-# Based on: https://portingguide.readthedocs.io/en/latest/builtins.html#removed-file
-try:
- # Python 2
- file_types = (file, IOBase,)
-except NameError:
- # "file" isn't a built-in type in Python 3
- file_types = (IOBase,)
-
-# Exporting types and functions from six
-string_types = six.string_types
-integer_types = six.integer_types
-class_types = six.class_types
-text_type = six.text_type
-binary_type = six.binary_type
-
-def ensure_binary(s, encoding='utf-8', errors='strict'):
- return six.ensure_binary(s, encoding=encoding, errors=errors)
-
-def ensure_str(s, encoding='utf-8', errors='strict'):
- return six.ensure_str(s, encoding=encoding, errors=errors)
-
-def ensure_text(s, encoding='utf-8', errors='strict'):
- return six.ensure_text(s, encoding=encoding, errors=errors)
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-import os
-from configparser import ConfigParser
-from hailo_platform.common.paths_manager.paths import PackingInfo, PackingStatus, SDKPaths
-from hailo_platform.paths_manager.paths import PlatformPaths
-
-
-class ConfigFileNotFoundException(Exception):
- pass
-
-
-def get_home_hailo_dir():
- return os.path.expanduser('~/.hailo')
-
-def get_parsed_config_from_path(config_path=None):
- actual_config_path = _get_config_path_with_default(config_path)
- config = ConfigParser()
- with open(actual_config_path, 'r') as config_file:
- config.read_file(config_file)
- return config
-
-
-def _get_config_path_with_default(config_path=None):
- if config_path is not None and os.path.isfile(config_path):
- return config_path
- default_path = _get_config_path()
- if os.path.isfile(default_path):
- return default_path
- raise ConfigFileNotFoundException('Could not find configuration file at default path: {}.'.format(default_path))
-
-
-def _get_config_path():
- config_file_name = 'config'
-
- if PackingInfo().status in [PackingStatus.unpacked]:
- full_path = os.path.join(SDKPaths().join_sdk('../'), config_file_name)
- if os.path.exists(full_path):
- return full_path
- #This is a CI nightly workaround because we are in unpack mode but installing whl's
- #In this case SDKPaths() is inside the site packages and not the sdk root. the workaround is to look for local dir
- elif os.path.exists(config_file_name):
- return config_file_name
-
- elif PackingInfo().status in [PackingStatus.standalone_platform]:
- full_path = os.path.join(PlatformPaths().join_platform('../../'), config_file_name)
- if os.path.exists(full_path) and os.path.isfile(full_path):
- return full_path
-
- elif os.path.exists(config_file_name):
- return config_file_name
-
- return os.path.join(get_home_hailo_dir(), config_file_name)
+++ /dev/null
-#!/usr/bin/env python
-from builtins import object
-import os
-import shutil
-import copy
-from enum import Enum
-
-
-from hailo_platform.common.logger.logger import default_logger
-from future.utils import with_metaclass
-
-logger = default_logger()
-
-
-class ConfigStageNotSetException(Exception):
- pass
-
-class PackagingException(Exception):
- pass
-
-class Singleton(type):
- _instances = {}
-
- def __call__(cls, *args, **kwargs):
- if cls not in cls._instances:
- cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
- return cls._instances[cls]
-
-
-class PackingStatus(Enum):
- unpacked = 'unpacked'
- packed_server = 'packed_server'
- packed_client = 'packed_client'
- standalone_platform = 'standalone_platform'
-
-
-class PackingInfo(with_metaclass(Singleton, object)):
- def __init__(self):
- self._status = PackingStatus.unpacked
- self._has_graphviz = True
-
- def is_packed(self):
- return self._status not in [PackingStatus.unpacked]
-
- @property
- def status(self):
- return self._status
-
- @status.setter
- def status(self, val):
- self._status = val
-
- @property
- def has_graphviz(self):
- return self._has_graphviz
-
- @has_graphviz.setter
- def has_graphviz(self, val):
- self._has_graphviz = val
-
-
-class SDKPaths(with_metaclass(Singleton, object)):
- DEFAULT_BUILD_DIR = 'build'
-
- def __init__(self):
- self._build_dir_name = type(self).DEFAULT_BUILD_DIR
- self._build_dir_path = '.'
- self._custom_build_dir = None
-
- @property
- def _sdk_path(self):
- packaging_status = PackingInfo().status
- if packaging_status == PackingStatus.packed_server:
- import hailo_sdk_common
- return os.path.dirname(hailo_sdk_common.__path__[0])
- if packaging_status == PackingStatus.packed_client:
- return ''
- if packaging_status == PackingStatus.standalone_platform:
- raise PackagingException(
- 'the packaging status is \'standalone_platform\', and there was a call to a sdk method')
- import hailo_sdk_common
- return os.path.join(os.path.dirname(os.path.dirname(hailo_sdk_common.__path__[0])), 'sdk_server')
-
- @property
- def custom_build_dir(self):
- return self._custom_build_dir
-
- @custom_build_dir.setter
- def custom_build_dir(self, custom_build_dir):
- self._custom_build_dir = custom_build_dir
-
- def join_sdk(self, path):
- return os.path.join(self._sdk_path, path)
-
- def join_sdk_common(self, path):
- import hailo_sdk_common
- if PackingInfo().status == PackingStatus.packed_server:
- return self.join_sdk(os.path.join('hailo_sdk_common', path))
- return os.path.join(os.path.abspath(hailo_sdk_common.__path__[0]), path)
-
- def set_client_build_dir_path(self):
- if PackingInfo().status == PackingStatus.unpacked:
- self._build_dir_path = '../sdk_client'
-
- def set_server_build_dir_path(self):
- if PackingInfo().status == PackingStatus.unpacked:
- self._build_dir_path = '../sdk_server'
-
- def set_build_dir(self, build_dir_name=None, clean=False):
- self._build_dir_name = build_dir_name if build_dir_name is not None else type(self).DEFAULT_BUILD_DIR
- logger.debug('Build dir name: {}'.format(self._build_dir_name))
- build_dir = self.build_dir
- if os.path.exists(build_dir):
- if clean:
- logger.debug('Deleting build dir : {}'.format(build_dir))
- shutil.rmtree(build_dir)
- self._make_build_dir(build_dir)
- return
- self._make_build_dir(build_dir)
-
- @property
- def build_dir(self):
- if self._custom_build_dir:
- return self._custom_build_dir
- return os.path.join(self._sdk_path, self._build_dir_path, self._build_dir_name)
-
- def join_build_sdk(self, path):
- build_dir = self.build_dir
- if os.path.exists(build_dir):
- return os.path.join(build_dir, path)
- logger.debug('Creating build dir : {}'.format(build_dir))
- self._make_build_dir(build_dir)
- return os.path.join(build_dir, path)
-
- def _make_build_dir(self, build_dir):
- os.makedirs(build_dir)
-
-
-class BaseConfigDirs(object):
-
- DIRS_BUILD_ONLY = {
- 'outputs_dir': ['outputs'],
- 'bin_dir': ['bin'],
- 'weights_dir': ['data', 'weights'],
- 'inputs_dir': ['data', 'inputs'],
- }
-
- DIRS_SDK_ONLY = {}
-
- DIRS_BOTH = {}
-
- def __init__(self, hw_arch):
- self._hw_arch = hw_arch.name
- self._paths = SDKPaths()
- self._dirs = {}
- for d in [type(self).DIRS_BUILD_ONLY, type(self).DIRS_SDK_ONLY, type(self).DIRS_BOTH]:
- self._dirs.update(self._format_dirs(d))
-
- def get_dir(self, name, in_build=True):
- return self._join_base(self._dirs[name], in_build)
-
- def _format_dirs(self, input_dirs):
- result = {}
- for name, dir_path in input_dirs.items():
- result[name] = os.path.join(*dir_path).format(hw_arch=self._hw_arch)
- return result
-
- def _join_base(self, path, in_build=True):
- base_dir = self._paths.build_dir if in_build else 'microcode'
- whole_path = os.path.join(base_dir, path)
- return self._paths.join_sdk(whole_path)
-
- @property
- def build_dirs_keys(self):
- return list(type(self).DIRS_BUILD_ONLY.keys()) + list(type(self).DIRS_BOTH.keys())
-
-
-class BaseConfigPaths(BaseConfigDirs):
-
- PATHS = {
- 'bin': ['{bin_dir}', '{network_name}.mem'],
- }
-
- def __init__(self, hw_arch, model_name):
- super(BaseConfigPaths, self).__init__(hw_arch)
- self._model_name = model_name
- self._stage = None
- self._stage_only = False
-
- def set_stage(self, stage, stage_only=False):
- self._stage = stage
- self._stage_only = stage_only
-
- def get_path(self, path_name, in_build=True):
- template = os.path.join(*type(self).PATHS[path_name])
- if self._stage is None and '{network_name}' in template:
- raise ConfigStageNotSetException('Set the stage before trying to get paths')
- format_dict = copy.deepcopy(self._dirs)
- format_dict['model_name'] = self._model_name
- if self._stage_only:
- format_dict['network_name'] = self._stage
- else:
- format_dict['network_name'] = '{model_name}.{stage}'.format(
- model_name=self._model_name, stage=self._stage
- )
- config_path = template.format(**format_dict)
- return self._join_base(config_path, in_build)
+++ /dev/null
-#!/usr/bin/env python
-
-def get_version(package_name):
- # See: https://packaging.python.org/guides/single-sourcing-package-version/ (Option 5)
- # We assume that the installed package is actually the same one we import. This assumption may
- # break in some edge cases e.g. if the user modifies sys.path manually.
-
- # hailo_platform package has been renamed to hailort, but the import is still hailo_platform
- if package_name == "hailo_platform":
- package_name = "hailort"
- try:
- import pkg_resources
- return pkg_resources.get_distribution(package_name).version
- except:
- return 'unknown'
+++ /dev/null
-#!/usr/bin/env python
-from builtins import object
-import json
-
-from contextlib2 import contextmanager
-
-
-class InferenceTargetException(Exception):
- """Raised when an error related to the inference target has occurred."""
- pass
-
-
-class InferenceTargets(object):
- """Enum-like class with all inference targets supported by the Hailo SDK.
- See the classes themselves for details about each target.
- """
- UNINITIALIZED = 'uninitialized'
- SDK_NATIVE = 'sdk_native'
- SDK_NATIVE_CLIPPED = 'sdk_native_clipped'
- SDK_NUMERIC = 'sdk_numeric'
- SDK_DEBUG_PRECISE_NUMERIC = 'sdk_debug_precise_numeric'
- SDK_PARTIAL_NUMERIC = 'sdk_partial_numeric'
- SDK_FINE_TUNE = 'sdk_fine_tune'
- SDK_MIXED = 'sdk_mixed'
- HW_SIMULATION = 'hw_sim'
- HW_SIMULATION_MULTI_CLUSTER = 'hw_sim_mc'
- FPGA = 'fpga'
- UDP_CONTROLLER = 'udp'
- PCIE_CONTROLLER = 'pcie'
- HW_DRY = 'hw_dry'
- HW_DRY_UPLOAD = 'hw_dry_upload'
- UV_WORKER = 'uv'
- DANNOX = 'dannox'
-
-
-class InferenceObject(object):
- """Represents a target that can run models inference. The target can be either software based
- (eventually running on CPU/GPU), or Hailo hardware based.
-
- .. note:: This class should not be used directly. Use only its inherited classes.
- """
- NAME = InferenceTargets.UNINITIALIZED
- IS_NUMERIC = False
- IS_HARDWARE = False
- IS_SIMULATION = False
-
- def __new__(cls, *args, **kwargs):
- if cls.NAME == InferenceTargets.UNINITIALIZED:
- raise InferenceTargetException(
- '{} is an abstract target and cannot be used directly.'.format(cls.__name__))
- # object's __new__() takes no parameters
- return super(type(cls), cls).__new__(cls)
-
- def __init__(self):
- """Inference object constructor."""
- self._is_device_used = False
-
- def __eq__(self, other):
- return type(self).NAME == other
-
- # TODO: Required for Python2 BW compatibility (SDK-10038)
- # This impl' comes by default in Python3
- def __ne__(self, other):
- return not self.__eq__(other)
-
- @contextmanager
- def use_device(self, *args, **kwargs):
- """A context manager that should wrap any usage of the target."""
- self._is_device_used = True
- yield
- self._is_device_used = False
-
- @property
- def name(self):
- """str: The name of this target. Valid values are defined by
- :class:`InferenceObject <hailo_sdk_common.targets.inference_targets.InferenceTargets>`.
- """
- return type(self).NAME
-
- @property
- def is_numeric(self):
- """bool: Determines whether this target is working in numeric mode.
- """
- return type(self).IS_NUMERIC
-
- @property
- def is_hardware(self):
- """bool: Determines whether this target runs on a physical hardware device.
- """
- return type(self).IS_HARDWARE
-
- @property
- def is_simulation(self):
- """bool: Determines whether this target is used for HW simulation.
- """
- return type(self).IS_SIMULATION
-
- def _get_json_dict(self):
- json_dict = {'name': self.name,
- 'is_numeric': self.is_numeric,
- 'is_hardware': self.is_hardware,
- 'is_simulation': self.is_simulation}
- return json_dict
-
- def to_json(self):
- """Get a JSON representation of this object.
-
- Returns:
- str: A JSON dump.
- """
- return json.dumps(self._get_json_dict())
+++ /dev/null
-#!/usr/bin/env python
-from __future__ import print_function
-from builtins import object
-import subprocess
-
-from hailo_platform.common.logger.logger import default_logger
-
-
-class CmdUtilsBaseUtilError(Exception):
- pass
-
-
-class HailortCliUtilError(CmdUtilsBaseUtilError):
- pass
-
-
-# Note: CmdUtilsBaseUtil and CmdUtilsBaseUtilError are external dependencies in phase2-sdk/demos repo; don't change!
-class CmdUtilsBaseUtil(object):
- def __init__(self, args_parser):
- pass
-
-
-class Helper(CmdUtilsBaseUtil):
- def __init__(self, commands):
- self._commands = commands
-
- def __call__(self, parser):
- parser.set_defaults(func=self.run)
-
- def run(self, args):
- for command_name, (help_, _) in self._commands.items():
- print("{} - {}".format(command_name, help_))
-
-
-class HailortCliUtil(CmdUtilsBaseUtil):
- def __init__(self, args_parser, command):
- self._command = command
- self._logger = default_logger()
-
- @classmethod
- def _run_hailortcli(cls, binary_path, command, command_args):
- cmd_args = [binary_path, command] + command_args
-
- process = subprocess.Popen(cmd_args)
- try:
- _ = process.communicate()
- return process.returncode
- except KeyboardInterrupt:
- process.terminate()
- raise HailortCliUtilError('hailo has been interrupted by the user')
-
- def run(self, argv):
- hailortcli_cmd = 'hailortcli'
- self._logger.info('(hailo) Running command \'{}\' with \'hailortcli\''.format(self._command))
- return self._run_hailortcli(hailortcli_cmd, self._command, argv)
+++ /dev/null
-#!/usr/bin/env python
-from enum import Enum
-
-from hailo_platform.common.tools.cmd_utils.base_utils import CmdUtilsBaseUtil
-from hailo_platform.drivers.hw_object import EthernetDevice, PcieDevice
-from hailo_platform.common.logger.logger import default_logger
-from hailo_platform.drivers.hailort.pyhailort import PcieDeviceInfo, InternalPcieDevice
-
-logger = default_logger()
-
-class HailoCLITargets(Enum):
- udp = 'udp'
- pcie = 'pcie'
-
-
-class HailoDeviceCmdUtil(CmdUtilsBaseUtil):
- """
- Base class for any cmd utility that use a specific hailo device
- """
- def __init__(self, args_parser, set_target_args=True):
- super().__init__(args_parser)
- self._parser = args_parser
- if set_target_args:
- self.add_target_args(args_parser)
-
- def get_target(self, args):
- self.validate_args(args)
- target_type = self.get_target_type(args)
- if target_type == HailoCLITargets.udp.value:
- return EthernetDevice(args.ip)
- else:
- try:
- return PcieDevice(device_info=args.board_location)
- except Exception as e:
- logger.error('Internal PCIe error (No PCIe device connected?)')
- logger.error('Error code: {}'.format(e))
- raise
-
- def get_target_type(self, args):
- if args.target is not None:
- return args.target
-
- if args.ip is not None:
- # If IP is given, we assume that the target is udp
- return HailoCLITargets.udp.value
-
- # Otherwise the default target is pcie
- return HailoCLITargets.pcie.value
-
-
- def validate_args(self, args):
- if args.target == HailoCLITargets.udp.value:
- if not args.ip:
- self._parser.error('When using --target udp, you must supply --ip')
- if args.board_location:
- self._parser.error("When using --target udp, you must not supply --board-location")
-
- if args.board_location:
- all_devices = InternalPcieDevice.scan_devices()
- if args.board_location not in all_devices:
- self._parser.error('Device {} does not appear on your host, please run `hailo scan -d pcie` to see all available devices'
- .format(args.board_location))
-
- def add_target_args(self, args_parser):
- args_parser.add_argument('--target', type=str, choices=[t.value for t in HailoCLITargets],
- default=None, help='Device type to use')
- args_parser.add_argument('--ip', type=str, default=None, help='IP address of the target (udp)')
- args_parser.add_argument('-s', '--board-location', help=PcieDeviceInfo.BOARD_LOCATION_HELP_STRING,
- type=PcieDeviceInfo.argument_type)
+++ /dev/null
-{
- "_comment":
- [
- "This file defines the available fields of the firmwares config. It is not used to serialize any data.",
- "WARNING! DO NOT CHANGE THE ORDER OF THE DEFINITIONS AS IT WILL CHANGE THEIR GENERATED VALUES!"
- ],
- "version": 0,
- "categories":
- {
- "network":
- {
- "entries":
- {
- "should_use_dhcp": {"size": 1, "deserialize_as": "bool"},
- "mac_address": {"size": 1, "length": 6, "deserialize_as": "mac_address"},
- "static_ip_address": {"size": 4, "deserialize_as": "ipv4"},
- "static_gw_address": {"size": 4, "deserialize_as": "ipv4"},
- "static_netmask": {"size": 4, "deserialize_as": "ipv4"},
- "rx_pause_frames_enable": {"size": 1, "deserialize_as": "bool"}
- }
- },
- "system":
- {
- "entries":
- {
- "name": {"size": 1, "length": 32, "deserialize_as": "str"},
- "app_watchdog_enable": {"size": 1, "deserialize_as": "bool"},
- "app_watchdog_cycles": {"size": 4, "deserialize_as": "int"},
- "core_watchdog_enable": {"size": 1, "deserialize_as": "bool"},
- "core_watchdog_cycles": {"size": 4, "deserialize_as": "int"},
- "watchdog_mode" : {"size": 1, "deserialize_as": "watchdog_mode"},
- "max_neural_network_core_clock_rate": {"size": 4, "deserialize_as": "clock_frequency"},
- "supported_aspm_states": {"size": 1, "deserialize_as": "supported_aspm_states"},
- "bus_0_i2c_speed": {"size": 1, "deserialize_as": "i2c_speed"},
- "bus_1_i2c_speed": {"size": 1, "deserialize_as": "i2c_speed"},
- "bus_2_i2c_speed": {"size": 1, "deserialize_as": "i2c_speed"},
- "bus_3_i2c_speed": {"size": 1, "deserialize_as": "i2c_speed"},
- "supported_aspm_l1_substates": {"size": 1, "deserialize_as": "supported_aspm_l1_substates"},
- "overcurrent_parameters_source": {"size": 1, "deserialize_as": "overcurrent_parameters_source"},
- "overcurrent_monitoring_red_threshold": {"size": 4, "deserialize_as": "int"},
- "overcurrent_conversion_time_microseconds": {"size": 4, "deserialize_as": "conversion_time"},
- "temperature_parameters_source": {"size": 1, "deserialize_as": "temperature_parameters_source"},
- "temperature_red_threshold": {"size": 1, "deserialize_as": "int"},
- "temperature_red_hysteresis_threshold": {"size": 1, "deserialize_as": "int"},
- "temperature_orange_threshold": {"size": 1, "deserialize_as": "int"},
- "temperature_orange_hysteresis_threshold": {"size": 1, "deserialize_as": "int"},
- "temperature_throttling_enable": {"size": 1, "deserialize_as": "bool"},
- "overcurrent_monitoring_orange_threshold_enable": {"size": 1, "deserialize_as": "bool"}
- }
- },
- "control":
- {
- "entries":
- {
- "udp_port": {"size": 2, "deserialize_as": "int"}
- }
- },
- "d2h_event":
- {
- "entries":
- {
- "host_udp_port": {"size": 2, "deserialize_as": "int"},
- "src_udp_port": {"size": 2, "deserialize_as": "int"},
- "host_ip_address": {"size": 4, "deserialize_as": "ipv4"},
- "connection_type": {"size": 1, "deserialize_as": "bool"}
- }
- },
- "logger":
- {
- "entries":
- {
- "send_via_pci": {"size": 1, "deserialize_as": "bool"},
- "send_via_uart": {"size": 1, "deserialize_as": "bool"},
- "logger_level": {"size": 4, "deserialize_as": "logger_level"}
- }
- }
- }
-}
-
#!/usr/bin/env python
-""":class:`~hailo_platform.drivers.hw_object.HailoHWObject` is the high level base class of the
-platform API. :class:`~hailo_platform.drivers.hw_object.PcieDevice` inherits from it
-and implements control and dataflow over PCIe.
-"""
+from warnings import warn
+warn("Importing from 'hailo_platform.drivers' is deprecated, One should import from 'hailo_platform' module directly.", DeprecationWarning, stacklevel=2)
\ No newline at end of file
-#!/usr/bin/env python
-
-"""Control operations for the Hailo hardware device."""
-import struct
-from builtins import object
-from abc import ABCMeta, abstractmethod
-from future.utils import with_metaclass
-
-from hailo_platform.drivers.hailo_controller.hailo_control_protocol import HailoResetTypes, DeviceArchitectureTypes
-from hailo_platform.drivers.hailo_controller.power_measurement import SamplingPeriod, AveragingFactor, DvmTypes, PowerMeasurementTypes, DEFAULT_POWER_MEASUREMENT_DELAY_PERIOD_MS
-from hailo_platform.drivers.hailort.pyhailort import Control, InternalPcieDevice
-from hailo_platform.common.logger.logger import default_logger
-
-class ControlObjectException(Exception):
- """Raised on illegal ContolObject operation."""
- pass
-
-
-class FirmwareUpdateException(Exception):
- pass
-
-
-class HailoControl(with_metaclass(ABCMeta, object)):
- """Control object that sends control operations to a Hailo hardware device."""
-
- def __init__(self):
- """Initializes a new HailoControl object."""
- self._logger = default_logger()
- self._controller = None
-
- @abstractmethod
- def open(self):
- """Initializes the resources needed for using a control device."""
- pass
-
- @abstractmethod
- def close(self):
- """Releases the resources that were allocated for the control device."""
- pass
-
- def configure(self, hef, configure_params_by_name={}):
- """
- Configures device from HEF object.
-
- Args:
- hef (:class:`~hailo_platform.drivers.hailort.pyhailort.HEF`): HEF to configure the
- device from.
- configure_params_by_name (dict, optional): Maps between each net_group_name to
- configure_params. In case of a mismatch with net_groups_names, default params will
- be used.
- """
- return self._controller.configure_device_from_hef(hef, configure_params_by_name)
-
- @abstractmethod
- def chip_reset(self):
- """Resets the device (chip reset)."""
- pass
-
- @abstractmethod
- def read_memory(self, address, data_length):
- """Reads memory from the Hailo chip.
- Byte order isn't changed. The core uses little-endian byte order.
-
- Args:
- address (int): Physical address to read from.
- data_length (int): Size to read in bytes.
-
- Returns:
- list of str: Memory read from the chip, each index in the list is a byte.
- """
- pass
-
- @abstractmethod
- def write_memory(self, address, data_buffer):
- """Write memory to Hailo chip.
- Byte order isn't changed. The core uses little-endian byte order.
-
- Args:
- address (int): Physical address to write to.
- data_buffer (list of str): Data to write.
- """
- pass
-
-
-class HcpControl(HailoControl):
- """Control object that uses the HCP protocol for controlling the device."""
-
- WORD_SIZE = 4
-
-
- def __init__(self):
- super(HcpControl, self).__init__()
-
- @property
- def device_id(self):
- """Getter for the device_id.
-
- Returns:
- str: A string ID of the device. BDF for PCIe devices, MAC address for Ethernet devices, "Core" for core devices.
- """
- return self._device_id
-
- def open(self):
- """Initializes the resources needed for using a control device."""
- pass
-
- def close(self):
- """Releases the resources that were allocated for the control device."""
- pass
-
- def chip_reset(self):
- """Resets the device (chip reset)."""
- return self._controller.reset(reset_type=HailoResetTypes.CHIP)
-
- def nn_core_reset(self):
- """Resets the nn_core."""
- return self._controller.reset(reset_type=HailoResetTypes.NN_CORE)
-
- def soft_reset(self):
- """reloads the device firmware (soft reset)"""
- return self._controller.reset(reset_type=HailoResetTypes.SOFT)
-
- def forced_soft_reset(self):
- """reloads the device firmware (forced soft reset)"""
- return self._controller.reset(reset_type=HailoResetTypes.FORCED_SOFT)
-
- def read_memory(self, address, data_length):
- """Reads memory from the Hailo chip. Byte order isn't changed. The core uses little-endian
- byte order.
-
- Args:
- address (int): Physical address to read from.
- data_length (int): Size to read in bytes.
-
- Returns:
- list of str: Memory read from the chip, each index in the list is a byte
- """
- return self._controller.read_memory(address, data_length)
-
- def write_memory(self, address, data_buffer):
- """Write memory to Hailo chip. Byte order isn't changed. The core uses little-endian byte
- order.
-
- Args:
- address (int): Physical address to write to.
- data_buffer (list of str): Data to write.
- """
- return self._controller.write_memory(address, data_buffer)
-
- def power_measurement(self, dvm=DvmTypes.AUTO, measurement_type=PowerMeasurementTypes.AUTO):
- """Perform a single power measurement on an Hailo chip. It works with the default settings
- where the sensor returns a new value every 2.2 ms without averaging the values.
-
- Args:
- dvm (:class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes`):
- Which DVM will be measured. Default (:class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes.AUTO`) will be different according to the board: \n
- Default (:class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes.AUTO`) for EVB is an approximation to the total power consumption of the chip in PCIe setups.
- It sums :class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes.VDD_CORE`,
- :class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes.MIPI_AVDD` and :class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes.AVDD_H`.
- Only :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes.POWER` can measured with this option. \n
- Default (:class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes.AUTO`) for platforms supporting current monitoring (such as M.2 and mPCIe): :class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes.OVERCURRENT_PROTECTION`
- measurement_type
- (:class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes`):
- The type of the measurement.
-
- Returns:
- float: The measured power. \n
- For :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes`: \n
- - :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes.SHUNT_VOLTAGE`: Unit is mV. \n
- - :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes.BUS_VOLTAGE`: Unit is mV. \n
- - :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes.POWER`: Unit is W. \n
- - :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes.CURRENT`: Unit is mA. \n
-
-
- Note:
- This function can perform measurements for more than just power. For all supported
- measurement types, please look at
- :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes`.
- """
- if self.device_id.device_architecture != DeviceArchitectureTypes.HAILO8_B0:
- raise ControlObjectException("Invalid device architecture: {}".format(self.device_id.device_architecture))
- return self._controller.power_measurement(dvm, measurement_type)
-
- def start_power_measurement(self, delay=DEFAULT_POWER_MEASUREMENT_DELAY_PERIOD_MS, averaging_factor=AveragingFactor.AVERAGE_256, sampling_period=SamplingPeriod.PERIOD_1100us):
- """Start performing a long power measurement.
-
- Args:
- delay (int): Amount of time between each measurement interval (in milliseconds) This
- time period is sleep time of the core. The default value depends on the other
- default values, plus a factor of 20 percent.
- averaging_factor (:class:`~hailo_platform.drivers.hailort.pyhailort.AveragingFactor`):
- Number of samples per time period, sensor configuration value.
- sampling_period (:class:`~hailo_platform.drivers.hailort.pyhailort.SamplingPeriod`):
- Related conversion time, sensor configuration value. The sensor samples the power
- every ``sampling_period`` [ms] and averages every ``averaging_factor`` samples. The
- sensor provides a new value every: 2 * sampling_period * averaging_factor [ms]. The
- firmware wakes up every ``delay`` [ms] and checks the sensor. If there is a new
- value to read from the sensor, the firmware reads it. Note that the average
- calculated by the firmware is "average of averages", because it averages values
- that have already been averaged by the sensor.
- """
- return self._controller.start_power_measurement(delay, averaging_factor, sampling_period)
-
- def stop_power_measurement(self):
- """Stop performing a long power measurement. Deletes all saved results from the firmware.
- Calling the function eliminates the start function settings for the averaging the samples,
- and returns to the default values, so the sensor will return a new value every 2.2 ms
- without averaging values.
- """
- return self._controller.stop_power_measurement()
-
- def set_power_measurement(self, index, dvm=DvmTypes.AUTO, measurement_type=PowerMeasurementTypes.AUTO):
- """Set parameters for long power measurement on an Hailo chip.
-
- Args:
- index (int): Index of the buffer on the firmware the data would be saved at.
- dvm (:class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes`):
- Which DVM will be measured. Default (:class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes.AUTO`) will be different according to the board: \n
- Default (:class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes.AUTO`) for EVB is an approximation to the total power consumption of the chip in PCIe setups.
- It sums :class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes.VDD_CORE`,
- :class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes.MIPI_AVDD` and :class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes.AVDD_H`.
- Only :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes.POWER` can measured with this option. \n
- Default (:class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes.AUTO`) for platforms supporting current monitoring (such as M.2 and mPCIe): :class:`~hailo_platform.drivers.hailort.pyhailort.DvmTypes.OVERCURRENT_PROTECTION`
- measurement_type
- (:class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes`):
- The type of the measurement.
-
- Note:
- This function can perform measurements for more than just power. For all supported measurement types
- view :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes`
- """
- return self._controller.set_power_measurement(index, dvm, measurement_type)
-
- def get_power_measurement(self, index, should_clear=True):
- """Read measured power from a long power measurement
-
- Args:
- index (int): Index of the buffer on the firmware the data would be saved at.
- should_clear (bool): Flag indicating if the results saved at the firmware will be deleted after reading.
-
- Returns:
- :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementData`:
- Object containing measurement data \n
- For :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes`: \n
- - :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes.SHUNT_VOLTAGE`: Unit is mV. \n
- - :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes.BUS_VOLTAGE`: Unit is mV. \n
- - :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes.POWER`: Unit is W. \n
- - :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes.CURRENT`: Unit is mA. \n
-
- Note:
- This function can perform measurements for more than just power.
- For all supported measurement types view
- :class:`~hailo_platform.drivers.hailort.pyhailort.PowerMeasurementTypes`.
- """
- if self.device_id.device_architecture != DeviceArchitectureTypes.HAILO8_B0:
- raise ControlObjectException("Invalid device architecture: {}".format(self.device_id.device_architecture))
- return self._controller.get_power_measurement(
- index,
- should_clear=should_clear)
-
- def _examine_user_config(self):
- return self._controller.examine_user_config()
-
- def read_user_config(self):
- """Read the user configuration section as binary data.
-
- Returns:
- str: User config as a binary buffer.
- """
- return self._controller.read_user_config()
-
- def write_user_config(self, configuration):
- """Write the user configuration.
-
- Args:
- configuration (str): A binary representation of a Hailo device configuration.
- """
- return self._controller.write_user_config(configuration)
-
- def _erase_user_config(self):
- return self._controller.erase_user_config()
-
- def read_board_config(self):
- """Read the board configuration section as binary data.
-
- Returns:
- str: Board config as a binary buffer.
- """
- return self._controller.read_board_config()
-
- def write_board_config(self, configuration):
- """Write the static confuration.
-
- Args:
- configuration (str): A binary representation of a Hailo device configuration.
- """
- return self._controller.write_board_config(configuration)
-
- def identify(self):
- """Gets the Hailo chip identification.
-
- Returns:
- class HailoIdentifyResponse with Protocol version.
- """
- return self._controller.identify()
-
- def core_identify(self):
- """Gets the Core Hailo chip identification.
-
- Returns:
- class HailoIdentifyResponse with Protocol version.
- """
- return self._controller.core_identify()
-
- def set_fw_logger(self, level, interface_mask):
- """Configure logger level and interface of sending.
-
- Args:
- level (FwLoggerLevel): The minimum logger level.
- interface_mask (int): Output interfaces (mix of FwLoggerInterface).
- """
- return self._controller.set_fw_logger(level, interface_mask)
-
- def set_throttling_state(self, should_activate):
- """Change throttling state of temperature protection component.
-
- Args:
- should_activate (bool): Should be true to enable or false to disable.
- """
- return self._controller.set_throttling_state(should_activate)
-
- def get_throttling_state(self):
- """Get the current throttling state of temperature protection component.
-
- Returns:
- bool: true if temperature throttling is enabled, false otherwise.
- """
- return self._controller.get_throttling_state()
-
- def _set_overcurrent_state(self, should_activate):
- """Control whether the overcurrent protection is enabled or disabled.
-
- Args:
- should_activate (bool): Should be true to enable or false to disable.
- """
- return self._controller._set_overcurrent_state(should_activate)
-
- def _get_overcurrent_state(self):
- """Get the overcurrent protection state.
-
- Returns:
- bool: true if overcurrent protection is enabled, false otherwise.
- """
- return self._controller._get_overcurrent_state()
-
- def i2c_write(self, slave, register_address, data):
- """Write data to an I2C slave.
-
- Args:
- slave (:class:`hailo_platform.drivers.hailo_controller.i2c_slaves.I2CSlave`): I2C slave
- configuration.
- register_address (int): The address of the register to which the data will be written.
- data (str): The data that will be written.
- """
- return self._controller.i2c_write(slave, register_address, data)
-
- def i2c_read(self, slave, register_address, data_length):
- """Read data from an I2C slave.
-
- Args:
- slave (:class:`hailo_platform.drivers.hailo_controller.i2c_slaves.I2CSlave`): I2C slave
- configuration.
- register_address (int): The address of the register from which the data will be read.
- data_length (int): The number of bytes to read.
-
- Returns:
- str: Data read from the I2C slave.
- """
- return self._controller.i2c_read(slave, register_address, data_length)
-
- def read_register(self, address):
- """Read the value of a register from a given address.
-
- Args:
- address (int): Address to read register from.
-
- Returns:
- int: Value of the register
- """
- register_value, = struct.unpack('!I', self.read_memory(address, type(self).WORD_SIZE))
- return register_value
-
- def set_bit(self, address, bit_index):
- """Set (turn on) a specific bit at a register from a given address.
-
- Args:
- address (int) : Address of the register to modify.
- bit_index (int) : Index of the bit that would be set.
- """
- register_value = self.read_register(address)
- register_value |= 1 << bit_index
- self.write_memory(address, struct.pack('!I', register_value))
-
- def reset_bit(self, address, bit_index):
- """Reset (turn off) a specific bit at a register from a given address.
-
- Args:
- address (int) : Address of the register to modify.
- bit_index (int) : Index of the bit that would be reset.
- """
- register_value = self.read_register(address)
- register_value &= ~(1 << bit_index)
- self.write_memory(address, struct.pack('!I', register_value))
-
- def firmware_update(self, firmware_binary, should_reset=True):
- """Update firmware binary on the flash.
-
- Args:
- firmware_binary (bytes): firmware binary stream.
- should_reset (bool): Should a reset be performed after the update (to load the new firmware)
- """
- return self._controller.firmware_update(firmware_binary, should_reset)
-
- def second_stage_update(self, second_stage_binary):
- """Update second stage binary on the flash
-
- Args:
- second_stage_binary (bytes): second stage binary stream.
- """
- return self._controller.second_stage_update(second_stage_binary)
-
- def store_sensor_config(self, section_index, reset_data_size, sensor_type, config_file_path,
- config_height=0, config_width=0, config_fps=0, config_name=None):
-
- """Store sensor configuration to Hailo chip flash memory.
-
- Args:
- section_index (int): Flash section index to write to. [0-6]
- reset_data_size (int): Size of reset configuration.
- sensor_type (:class:`~hailo_platform.drivers.hailort.pyhailort.SensorConfigTypes`): Sensor type.
- config_file_path (str): Sensor configuration file path.
- config_height (int): Configuration resolution height.
- config_width (int): Configuration resolution width.
- config_fps (int): Configuration FPS.
- config_name (str): Sensor configuration name.
- """
- if config_name is None:
- config_name = "UNINITIALIZED"
-
- return self._controller.sensor_store_config(section_index, reset_data_size, sensor_type, config_file_path,
- config_height, config_width, config_fps, config_name)
-
- def store_isp_config(self, reset_config_size, isp_static_config_file_path, isp_runtime_config_file_path,
- config_height=0, config_width=0, config_fps=0, config_name=None):
- """Store sensor isp configuration to Hailo chip flash memory.
-
- Args:
- reset_config_size (int): Size of reset configuration.
- isp_static_config_file_path (str): Sensor isp static configuration file path.
- isp_runtime_config_file_path (str): Sensor isp runtime configuration file path.
- config_height (int): Configuration resolution height.
- config_width (int): Configuration resolution width.
- config_fps (int): Configuration FPS.
- config_name (str): Sensor configuration name.
- """
- if config_name is None:
- config_name = "UNINITIALIZED"
-
- return self._controller.store_isp_config(reset_config_size, config_height, config_width,
- config_fps, isp_static_config_file_path, isp_runtime_config_file_path, config_name)
-
- def get_sensor_sections_info(self):
- """Get sensor sections info from Hailo chip flash memory.
-
- Returns:
- Sensor sections info read from the chip flash memory.
- """
- return self._controller.sensor_get_sections_info()
-
- def sensor_set_generic_i2c_slave(self, slave_address, register_address_size, bus_index, should_hold_bus, endianness):
- """Set a generic I2C slave for sensor usage.
-
- Args:
- sequence (int): Request/response sequence.
- slave_address (int): The address of the I2C slave.
- register_address_size (int): The size of the offset (in bytes).
- bus_index (int): The number of the bus the I2C slave is behind.
- should_hold_bus (bool): Hold the bus during the read.
- endianness (:class:`~hailo_platform.drivers.hailort.pyhailort.Endianness`):
- Big or little endian.
- """
- return self._controller.sensor_set_generic_i2c_slave(slave_address, register_address_size, bus_index, should_hold_bus, endianness)
-
- def set_sensor_i2c_bus_index(self, sensor_type, i2c_bus_index):
- """Set the I2C bus to which the sensor of the specified type is connected.
-
- Args:
- sensor_type (:class:`~hailo_platform.drivers.hailort.pyhailort.SensorConfigTypes`): The sensor type.
- i2c_bus_index (int): The I2C bus index of the sensor.
- """
- return self._controller.sensor_set_i2c_bus_index(sensor_type, i2c_bus_index)
-
- def load_and_start_sensor(self, section_index):
- """Load the configuration with I2C in the section index.
-
- Args:
- section_index (int): Flash section index to load config from. [0-6]
- """
- return self._controller.sensor_load_and_start_config(section_index)
-
- def reset_sensor(self, section_index):
- """Reset the sensor that is related to the section index config.
-
- Args:
- section_index (int): Flash section index to reset. [0-6]
- """
- return self._controller.sensor_reset(section_index)
-
- def wd_enable(self, cpu_id):
- """Enable firmware watchdog.
-
- Args:
- cpu_id (:class:`~hailo_platform.drivers.hailort.pyhailort.HailoCpuId`): 0 for App CPU, 1 for Core CPU.
- """
- self._controller.wd_enable(cpu_id)
-
- def wd_disable(self, cpu_id):
- """Disable firmware watchdog.
-
- Args:
- cpu_id (:class:`~hailo_platform.drivers.hailort.pyhailort.HailoCpuId`): 0 for App CPU, 1 for Core CPU.
- """
- self._controller.wd_disable(cpu_id)
-
- def wd_config(self, cpu_id, wd_cycles, wd_mode):
- """Configure a firmware watchdog.
-
- Args:
- cpu_id (:class:`~hailo_platform.drivers.hailort.pyhailort.HailoCpuId`): 0 for App CPU, 1 for Core CPU.
- wd_cycles (int): number of cycles until watchdog is triggered.
- wd_mode (int): 0 - HW/SW mode, 1 - HW only mode
- """
- return self._controller.wd_config(cpu_id, wd_cycles, wd_mode)
-
- def previous_system_state(self, cpu_id):
- """Read the FW previous system state.
-
- Args:
- cpu_id (:class:`~hailo_platform.drivers.hailort.pyhailort.HailoCpuId`): 0 for App CPU, 1 for Core CPU.
- """
- return self._controller.previous_system_state(cpu_id)
-
- def get_chip_temperature(self):
- """Returns the latest temperature measurements from the 2 internal temperature sensors of the Hailo chip.
-
- Returns:
- :class:`~hailo_platform.drivers.hailort.pyhailort.TemperatureInfo`:
- Temperature in celsius of the 2 internal temperature sensors (TS), and a sample
- count (a running 16-bit counter)
- """
- return self._controller.get_chip_temperature()
-
- def get_extended_device_information(self):
- return self._controller.get_extended_device_information()
-
- def _get_health_information(self):
- return self._controller._get_health_information()
-
- def set_pause_frames(self, rx_pause_frames_enable):
- """Enable/Disable Pause frames.
-
- Args:
- rx_pause_frames_enable (bool): False for disable, True for enable.
- """
- self._controller.set_pause_frames(rx_pause_frames_enable)
-
- def test_chip_memories(self):
- """test all chip memories using smart BIST
-
- """
- self._controller.test_chip_memories()
-
- def _get_device_handle(self):
- return self._controller._get_device_handle()
-
-class UdpHcpControl(HcpControl):
- """Control object that uses a HCP over UDP controller interface."""
-
- def __init__(self, remote_ip, device=None, remote_control_port=22401, retries=2, response_timeout_seconds=10.0, ignore_socket_errors=False):
- """Initializes a new UdpControllerControl object.
-
- Args:
- remote_ip (str): The IPv4 address of the remote Hailo device (X.X.X.X).
- remote_control_port (int, optional): The port that the remote Hailo device listens on.
- response_timeout_seconds (float, optional): Number of seconds to wait until a response is received.
- ignore_socket_errors (bool, optional): Ignore socket error (might be usefull for debugging).
- """
- super(UdpHcpControl, self).__init__()
-
- # In the C API we define the total amount of attempts, instead of the amount of retries.
- max_number_of_attempts = retries + 1
- self._controller = Control(Control.Type.ETH, remote_ip, remote_control_port, response_timeout_seconds=response_timeout_seconds, max_number_of_attempts=max_number_of_attempts)
- self.set_udp_device(device)
- self._device_id = self.identify()
-
- def set_udp_device(self, device):
- self._controller.set_device(device)
-
-
-class PcieHcpControl(HcpControl):
- """Control object that uses a HCP over PCIe controller interface."""
-
- def __init__(self, device=None, device_info=None):
- """Initializes a new HailoPcieController object."""
- super(PcieHcpControl, self).__init__()
-
- if device_info is None:
- device_info = InternalPcieDevice.scan_devices()[0]
-
- self._controller = Control(Control.Type.PCIE, None, None, pcie_device_info=device_info)
- self.set_pcie_device(device)
- self._device_id = self.identify()
-
- def release(self):
- if self._controller is None:
- return
- self._controller.release()
- self._controller = None
-
- def set_pcie_device(self, pcie_device):
- """Prepare the pcie device to be used after creating it."""
- self._controller.set_device(pcie_device)
-
- def set_notification_callback(self, callback_func, notification_id, opaque):
- """Set a callback function to be called when a notification is received.
-
- Args:
- callback_func (function): Callback function with the parameters (device, notification, opaque).
- Note that throwing exceptions is not supported and will cause the program to terminate with an error!
- notification_id (NotificationId): Notification ID to register the callback to.
- opauqe (object): User defined data.
-
- Note:
- The notifications thread is started and closed in the use_device() context, so
- notifications can only be received there.
- """
- return self._controller.set_notification_callback(callback_func, notification_id, opaque)
-
- def remove_notification_callback(self, notification_id):
- """Remove a notification callback which was already set.
-
- Args:
- notification_id (NotificationId): Notification ID to remove the callback from.
- """
- return self._controller.remove_notification_callback(notification_id)
+from hailo_platform.pyhailort.control_object import * # noqa F401
-#!/usr/bin/env python
-from builtins import str
-import netifaces as ni
-
-from netaddr import IPAddress, IPNetwork
-
-
-# As defined in sockios.h
-SIOCGIFTXQLEN = 0x8942
-# Interface name is 16 bytes (including NULL)
-SIOCGIFTXQLEN_FMT = "16sI"
-
-class NoInterfaceError(Exception):
- """Raised by get_interface_from_ip when no matching interface was found"""
- pass
-
-def get_interface_from_ip(ip_address):
- """Returns the interface name associated with the given ip addressself.
-
- Args:
- ip_address (str): the IP address to query.
-
- Returns:
- str: The name of the interface matching the given IP address.
- """
-
- skipped_ifaces = []
- for interface in ni.interfaces():
- if ni.AF_INET not in ni.ifaddresses(interface):
- skipped_ifaces.append(interface)
- continue
- af_inet_values = ni.ifaddresses(interface)[ni.AF_INET][0]
- ip_addr, netmask = af_inet_values['addr'], af_inet_values['netmask']
- if is_ip_in_network(ip_addr, netmask, ip_address):
- return str(interface)
-
- raise NoInterfaceError('No interface for {} found among {}'.format(ip_address, skipped_ifaces))
-
-
-def get_interface_address(interface_name):
- """Returns the interface address associated with the given interface name.
-
- Args:
- interface_name (str): the name of the interface to query.
-
- Returns:
- str: The IP address of the interface matching the given interface_name.
- """
- af_inet_values = ni.ifaddresses(interface_name)[ni.AF_INET][0]
- return af_inet_values['addr']
-
-
-def is_ip_in_network(network_ip, netmask, ip_in_question):
- """Checks whether an IP address is located in a given network.
-
- Args:
- network_ip (str): the IP address of the network interface.
- netmask (str): the netmask of the given networkself.
- ip_in_question (str): the IP address to compare against the network.
-
- Returns:
- bool: whether the IP address belongs to the given network.
- """
-
- netmask_bits = IPAddress(netmask).netmask_bits()
- return IPAddress(ip_in_question) in IPNetwork('{}/{}'.format(network_ip, netmask_bits))
+from hailo_platform.pyhailort.ethernet_utils import * # noqa F401
\ No newline at end of file
#!/usr/bin/env python
-"""
-.. module:: hailo_control_protocol
- :synopsis: Implements a Hailo Control Protocol message.
-"""
-
-from builtins import object
-from enum import Enum, IntEnum
-
-import struct
-
-# Supported protocol and Firmware version of current SDK.
-SUPPORTED_PROTOCOL_VERSION = 2
-SUPPORTED_FW_MAJOR = 4
-SUPPORTED_FW_MINOR = 6
-SUPPORTED_FW_REVISION = 0
-
-MEGA_MULTIPLIER = 1000.0 * 1000.0
-
-
-class HailoControlProtocolException(Exception):
- pass
-
-
-class DeviceArchitectureTypes(IntEnum):
- HAILO8_A0 = 0
- HAILO8_B0 = 1
- MERCURY_CA = 2
-
- def __str__(self):
- return self.name
-
-class BoardInformation(object):
- def __init__(self, protocol_version, fw_version_major, fw_version_minor, fw_version_revision,
- logger_version, board_name, is_release, device_architecture, serial_number, part_number, product_name):
- self.protocol_version = protocol_version
- self.firmware_version = HailoFirmwareVersion.construct_from_params(fw_version_major, fw_version_minor, fw_version_revision, is_release, HailoFirmwareType.APP)
- self.logger_version = logger_version
- self.board_name = board_name
- self.is_release = is_release
- self.device_architecture = DeviceArchitectureTypes(device_architecture)
- self.serial_number = serial_number
- self.part_number = part_number
- self.product_name = product_name
-
- def _string_field_str(self, string_field):
- # Return <Not Configured> if the string field is empty
- return string_field.rstrip('\x00') or "<Not Configured>"
-
- def __str__(self):
- """Returns:
- str: Human readable string.
- """
- return 'Control Protocol Version: {}\n' \
- 'Firmware Version: {}\n' \
- 'Logger Version: {}\n' \
- 'Board Name: {}\n' \
- 'Device Architecture: {}\n' \
- 'Serial Number: {}\n' \
- 'Part Number: {}\n' \
- 'Product Name: {}\n'.format(
- self.protocol_version,
- self.firmware_version,
- self.logger_version,
- self.board_name.rstrip('\x00'),
- str(self.device_architecture),
- self._string_field_str(self.serial_number),
- self._string_field_str(self.part_number),
- self._string_field_str(self.product_name))
-
- def __repr__(self):
- """Returns:
- str: Human readable string.
- """
- return self.__str__()
-
- @staticmethod
- def get_hw_arch_str(device_arch):
- if device_arch == DeviceArchitectureTypes.HAILO8_B0:
- return 'hailo8'
- elif device_arch == DeviceArchitectureTypes.MERCURY_CA:
- return 'mercury'
- else:
- raise HailoControlProtocolException("Unsupported device architecture.")
-
-class CoreInformation(object):
- def __init__(self, fw_version_major, fw_version_minor, fw_version_revision, is_release):
- self.firmware_version = HailoFirmwareVersion.construct_from_params(fw_version_major, fw_version_minor, fw_version_revision, is_release, HailoFirmwareType.CORE)
- self.is_release = is_release
-
- def __str__(self):
- """Returns:
- str: Human readable string.
- """
- return 'Core Firmware Version: {}'.format(
- self.firmware_version)
-
- def __repr__(self):
- """Returns:
- str: Human readable string.
- """
- return self.__str__()
-
-class TemperatureThrottlingLevel(object):
- def __init__(self, level_number, temperature_threshold, hysteresis_temperature_threshold, throttling_nn_clock_freq):
- self.level_number = level_number
- self.temperature_threshold = temperature_threshold
- self.hysteresis_temperature_threshold = hysteresis_temperature_threshold
- self.throttling_nn_clock_freq = throttling_nn_clock_freq
-
- def __str__(self):
- """Returns:
- str: Human readable string.
- """
- return 'Temperature Throttling Level {}: \n' \
- 'Temperature Threshold: {}\n' \
- 'Hysteresis Temperature Threshold: {}\n' \
- 'Throttling NN Clock Frequency: {}\n' \
- .format(self.level_number, self.temperature_threshold, self.hysteresis_temperature_threshold, self.throttling_nn_clock_freq)
-
- def __repr__(self):
- return self.__str__()
-
-class HealthInformation(object):
- def __init__(self, overcurrent_protection_active, current_overcurrent_zone, red_overcurrent_threshold, orange_overcurrent_threshold,
- temperature_throttling_active, current_temperature_zone, current_temperature_throttling_level,
- temperature_throttling_levels, orange_temperature_threshold, orange_hysteresis_temperature_threshold,
- red_temperature_threshold, red_hysteresis_temperature_threshold):
- self.overcurrent_protection_active = overcurrent_protection_active
- self.current_overcurrent_zone = current_overcurrent_zone
- self.red_overcurrent_threshold = red_overcurrent_threshold
- self.orange_overcurrent_threshold = orange_overcurrent_threshold
- self.temperature_throttling_active = temperature_throttling_active
- self.current_temperature_zone = current_temperature_zone
- self.current_temperature_throttling_level = current_temperature_throttling_level
- self.orange_temperature_threshold = orange_temperature_threshold
- self.orange_hysteresis_temperature_threshold = orange_hysteresis_temperature_threshold
- self.red_temperature_threshold = red_temperature_threshold
- self.red_hysteresis_temperature_threshold = red_hysteresis_temperature_threshold
-
- # Add TemperatureThrottlingLevel in case it has new throttling_nn_clock_freq. level_number can be used as only last
- # levels can be with the same freq
- self.temperature_throttling_levels = []
- if self.temperature_throttling_active:
- throttling_nn_clock_frequencies = []
- for level_number, temperature_throttling_level in enumerate(temperature_throttling_levels):
- if temperature_throttling_level.throttling_nn_clock_freq not in throttling_nn_clock_frequencies:
- throttling_nn_clock_frequencies.append(temperature_throttling_level.throttling_nn_clock_freq)
- self.temperature_throttling_levels.append(TemperatureThrottlingLevel(level_number,
- temperature_throttling_level.temperature_threshold,
- temperature_throttling_level.hysteresis_temperature_threshold,
- temperature_throttling_level.throttling_nn_clock_freq))
- def __repr__(self):
- return self.__str__()
-
- def __str__(self):
- """Returns:
- str: Human readable string.
- """
- temperature_throttling_levels_str = "\n".join(["\n\n{}\n".format(str(temperature_throttling_level)) for temperature_throttling_level in self.temperature_throttling_levels]) \
- if self.temperature_throttling_active else "<Temperature throttling is disabled>"
- return 'Overcurrent Protection Active: {}\n' \
- 'Overcurrent Protection Current Overcurrent Zone: {}\n' \
- 'Overcurrent Protection Red Threshold: {}\n' \
- 'Overcurrent Protection Orange Threshold: {}\n' \
- 'Temperature Protection Red Threshold: {}\n' \
- 'Temperature Protection Red Hysteresis Threshold: {}\n' \
- 'Temperature Protection Orange Threshold: {}\n' \
- 'Temperature Protection Orange Hysteresis Threshold: {}\n' \
- 'Temperature Protection Throttling State: {}\n' \
- 'Temperature Protection Current Zone: {}\n' \
- 'Temperature Protection Current Throttling Level: {}\n' \
- 'Temperature Protection Throttling Levels: {}' \
- .format(self.overcurrent_protection_active, self.current_overcurrent_zone, self.red_overcurrent_threshold,
- self.orange_overcurrent_threshold, self.red_temperature_threshold,
- self.red_hysteresis_temperature_threshold, self.orange_temperature_threshold,
- self.orange_hysteresis_temperature_threshold, self.temperature_throttling_active,
- self.current_temperature_zone, self.current_temperature_throttling_level, temperature_throttling_levels_str)
-
-class ExtendedDeviceInformation(object):
- def __init__(self, neural_network_core_clock_rate, supported_features, boot_source, lcs, soc_id, eth_mac_address, unit_level_tracking_id, soc_pm_values):
- self.neural_network_core_clock_rate = neural_network_core_clock_rate
- self.supported_features = SupportedFeatures(supported_features)
- self.boot_source = boot_source
- self.lcs = lcs
- self.soc_id = soc_id
- self.eth_mac_address = eth_mac_address
- self.unit_level_tracking_id = unit_level_tracking_id
- self.soc_pm_values = soc_pm_values
-
- def __str__(self):
- """Returns:
- str: Human readable string.
- """
- string = 'Neural Network Core Clock Rate: {}MHz\n' \
- '{}' \
- 'Boot source: {}\n' \
- 'LCS: {}\n'.format(
- self.neural_network_core_clock_rate / MEGA_MULTIPLIER,
- str(self.supported_features),
- str(self.boot_source.name),
- str(self.lcs))
- if any(self.soc_id):
- string += 'SoC ID: ' + (self.soc_id.hex())
-
- if any(self.eth_mac_address):
- string += '\nMAC Address: ' + (":".join("{:02X}".format(i) for i in self.eth_mac_address))
-
- if any(self.unit_level_tracking_id):
- string += '\nULT ID: ' + (self.unit_level_tracking_id.hex())
-
- if any(self.soc_pm_values):
- string += '\nPM Values: ' + (self.soc_pm_values.hex())
-
-
- return string
-
- def __repr__(self):
- """Returns:
- str: Human readable string.
- """
- return self.__str__()
-
-class HailoFirmwareMode(Enum):
- """Indication that firmware version is stable and official """
- DEVELOP = 'develop'
- RELEASE = 'release'
-
-
-class HailoFirmwareType(Enum):
- """Indication the firmware type """
- CORE = 'core'
- APP = 'app'
-
-
-class HailoResetTypes(Enum):
- """Defines the available reset types."""
- CHIP = 'chip'
- NN_CORE = 'nn_core'
- SOFT = 'soft'
- FORCED_SOFT = 'forced_soft'
-
-
-class HailoFirmwareVersion(object):
- """Represents a Hailo chip firmware version."""
- DEV_BIT = 0x80000000
- CORE_BIT = 0x08000000
- FW_VERSION_FORMAT = '<III'
-
- def __init__(self, firmware_version_buffer, is_release, fw_type):
- """Initialize a new Hailo Firmware Version object.
-
- Args:
- firmware_version_buffer (str): A buffer containing the firmware version struct.
- is_release (bool, optional): Flag indicating if firmware is at develop/release mode.
- None indicates unknown
- """
- self.major, self.minor, self.revision = struct.unpack(
- self.FW_VERSION_FORMAT,
- firmware_version_buffer)
-
- self.fw_type = fw_type
- self.mode = HailoFirmwareMode.RELEASE if is_release else HailoFirmwareMode.DEVELOP
-
- self.revision &= ~(self.CORE_BIT | self.DEV_BIT)
-
- def __str__(self):
- """Returns:
- str: Firmware version in a human readable format.
- """
- return '{}.{}.{} ({},{})'.format(self.major, self.minor, self.revision, self.mode.value, self.fw_type.value)
-
- @classmethod
- def construct_from_params(cls, major, minor, revision, is_release, fw_type):
- """Returns:
- class HailoFirmwareVersion : with the given Firmware version.
- """
- return cls(struct.pack(HailoFirmwareVersion.FW_VERSION_FORMAT, major, minor, revision), is_release, fw_type)
-
- @property
- def comparable_value(self):
- """A value that could be compared to other firmware versions."""
- return (self.major << 64) + (self.minor << 32) + (self.revision)
-
- def __hash__(self):
- return self.comparable_value
-
- def __eq__(self, other):
- return self.comparable_value == other.comparable_value
-
- # TODO: Required for Python2 BW compatibility (SDK-10038)
- # This impl' comes by default in Python3
- def __ne__(self, other):
- return not (self == other)
-
- def __lt__(self, other):
- return self.comparable_value < other.comparable_value
-
- def check_protocol_compatibility(self, other):
- return ((self.major == other.major) and (self.minor == other.minor))
-
-class SupportedFeatures(object):
- def __init__(self, supported_features):
- self.ethernet = supported_features.ethernet
- self.mipi = supported_features.mipi
- self.pcie = supported_features.pcie
- self.current_monitoring = supported_features.current_monitoring
- self.mdio = supported_features.mdio
-
- def _feature_str(self, feature_name, is_feature_enabled):
- return '{}: {}\n'.format(feature_name, 'Enabled' if is_feature_enabled else 'Disabled')
-
- def __str__(self):
- """Returns:
- str: Human readable string.
- """
- return 'Device supported features: \n' + \
- self._feature_str('Ethernet', self.ethernet) + \
- self._feature_str('MIPI', self.mipi) + \
- self._feature_str('PCIE', self.pcie) + \
- self._feature_str('Current Monitoring', self.current_monitoring) + \
- self._feature_str('MDIO', self.mdio)
-
- def __repr__(self):
- """Returns:
- str: Human readable string.
- """
- return self.__str__()
-
- def _is_feature_enabled(self, feature):
- return (self.supported_features & feature) != 0
+from hailo_platform.pyhailort.hailo_control_protocol import * # noqa F401
\ No newline at end of file
#!/usr/bin/env python
-from builtins import object
-import struct
-
-from hailo_platform.common.logger.logger import default_logger
-from hailo_platform.drivers.hailort.pyhailort import Endianness
-logger = default_logger()
-
-#: Variable which defines that the I2C slave is not behind a switch.
-NO_I2C_SWITCH = 5
-
-class I2CSlavesException(Exception):
- pass
-
-
-class I2CSlave(object):
- def __init__(self, name, bus_index, slave_address, switch_number=NO_I2C_SWITCH,
- register_address_size=1, endianness=Endianness.LITTLE_ENDIAN,
- should_hold_bus=False):
- """Initialize a class which describes an I2C slave.
-
- Args:
- name (str): The name of the I2C slave.
- bus_index (int): The bus number the I2C slave is connected to.
- slave_address (int): The address of the I2C slave.
- switch_number (int): The number of the switch the i2c salve is connected to.
- register_address_size (int): Slave register address length (in bytes).
- endianness (:class:`~hailo_platform.drivers.hailort.pyhailort.Endianness`): The endianness of the slave.
- should_hold_bus (bool): Should hold the bus during the read.
-
- """
- self._name = name
- self._bus_index = bus_index
- self._slave_address = slave_address
- self._switch_number = switch_number
- self._register_address_size = register_address_size
- self._endianness = endianness
- self._should_hold_bus = should_hold_bus
-
- def __repr__(self):
- # Returning '' for the sphinx doc
- return ''
-
- @property
- def name(self):
- """Get the name of the I2C slave.
-
- Returns:
- str: Name of the I2C slave.
- """
- return self._name
-
- @property
- def bus_index(self):
- """Get bus index the I2C slave is connected to.
-
- Returns:
- int: Index of the bus the I2C slave is connected to.
- """
- return self._bus_index
-
- @property
- def slave_address(self):
- """Get the address of the salve.
-
- Returns:
- int: The address of the I2C slave.
- """
- return self._slave_address
-
- @property
- def register_address_size(self):
- """Get the slave register address length (in bytes). This number represents how many bytes are in the
- register address the slave can access.
-
- Returns:
- int: Slave register address length.
-
- Note:
- Pay attention to the slave endianness (:class:`~hailo_platform.drivers.hailort.pyhailort.Endianness`).
- """
- return self._register_address_size
-
- @property
- def switch_number(self):
- """Get the switch number the slave is connected to.
-
- Returns:
- int: The number of the switch the I2C is behind.
-
- Note:
- If :data:`NO_I2C_SWITCH` is returned, it means the slave is not behind a switch.
- """
- return self._switch_number
-
- @property
- def endianness(self):
- """Get the slave endianness.
-
- Returns:
- :class:`~hailo_platform.drivers.hailort.pyhailort.Endianness`: The slave endianness.
- """
- return self._endianness
-
- @property
- def should_hold_bus(self):
- """Returns a Boolean indicating if the bus will be held while reading from the slave.
-
- Returns:
- bool: True if the bus would be held, otherwise False.
- """
- return self._should_hold_bus
-
-# DVM's
-#: Class which represents the MIPI AVDD I2C slave.
-I2C_SLAVE_MIPI_AVDD = I2CSlave("DVM_MIPI_AVDD", 0, 0x40)
-#: Class which represents the USB AVDD IO slave.
-I2C_SLAVE_USB_AVDD_IO = I2CSlave("DVM_USB_AVDD_IO", 0, 0x41)
-#: Class which represents the V_CORE slave.
-I2C_SLAVE_VDD_CORE = I2CSlave("DVM_VDD_CORE", 0, 0x42)
-#: Class which represents the VDD TOP slave.
-I2C_SLAVE_VDD_TOP = I2CSlave("DVM_VDD_TOP", 0, 0x43)
-#: Class which represents the MIPI AVDD_H I2C slave.
-I2C_SLAVE_MIPI_AVDD_H = I2CSlave("DVM_MIPI_AVDD_H", 0, 0x44)
-#: Class which represents the DVM USB AVDD IO HV slave.
-I2C_SLAVE_USB_AVDD_IO_HV = I2CSlave("DVM_USB_AVDD_IO_HV", 0, 0x45)
-#: Class which represents the DVM_VDDIO slave.
-I2C_SLAVE_VDD_IO = I2CSlave("DVM_VDD_IO", 0, 0x46)
-#: Class which represents the DVM_AVDD_H slave.
-I2C_SLAVE_AVDD_H = I2CSlave("DVM_AVDD_H", 0, 0x47)
-#: Class which represents the DVM_SDIO_VDDIO slave.
-I2C_SLAVE_SDIO_VDD_IO = I2CSlave("DVM_SDIO_VDD_IO", 0, 0x4d)
-
-#: Class which represents the DVM_SDIO_VDDIO slave.
-I2C_SLAVE_M_DOT_2_OVERCURREN_PROTECTION = I2CSlave("M_DOT_2_OVERCURREN_PROTECTION", 0, 0x40)
-
-#: Class which represents the I2S codec I2C slave.
-I2C_SLAVE_I2S_CODEC = I2CSlave("I2S_codec", 1, 0x18, should_hold_bus=True)
-
-#: Class which represents the I2C to gpio I2C slave.
-I2C_SLAVE_I2C_TO_GPIO = I2CSlave("I2C_to_GPIO", 0, 0x22)
-#: Class which represents the I2C switch slave.
-I2C_SLAVE_SWITCH = I2CSlave("I2C_SWITCH", 1, 0x70)
-
-#: Class which represents the I2C TEMP_sensor_0 slave.
-I2C_SLAVE_TEMP_SENSOR_0 = I2CSlave("TEMP_sensor_0", 0, 0x29)
-#: Class which represents the I2S TEMP_sensor_1 slave.
-I2C_SLAVE_TEMP_SENSOR_1 = I2CSlave("TEMP_sensor_1", 0, 0x2A)
-
-#: Class which represents the EEPROM I2C slave.
-I2C_SLAVE_EEPROM = I2CSlave("EEPROM", 0, 0x50, register_address_size=2,
- endianness=Endianness.BIG_ENDIAN)
-
-# External hardware
-#: Class which represents the raspicam I2C slave.
-I2C_SLAVE_RASPICAM = I2CSlave("RaspiCam", 1, 0x36, switch_number=1, register_address_size=2,
- endianness=Endianness.BIG_ENDIAN)
-
-I2C_SLAVE_ONSEMI_CAMERA_AR0220 = I2CSlave('Onsemi', 1, 0x10, switch_number=0, register_address_size=2,
- endianness=Endianness.BIG_ENDIAN)
-
-I2C_SLAVE_ONSEMI_CAMERA_AS0149 = I2CSlave('Onsemi', 1, (0x90 >> 1), switch_number=0, register_address_size=2,
- endianness=Endianness.BIG_ENDIAN)
-
-def set_i2c_switch(control_object, slave, slave_switch=None):
- """Set the I2C switch in order to perform actions from the I2C slave.
-
- Args:
- control_object (:class:`~hailo_platform.drivers.control_object.HcpControl`): Control object
- which communicates with the Hailo chip.
- slave (:class:`I2CSlave`): Slave which the switch is set for.
- slave_switch (:class:`I2CSlave`): The I2C slave for the switch it self. Defaults to
- :data:`I2C_SLAVE_SWITCH`.
- """
- I2C_SWITCH_REGISTER_SIZE = 1
- if NO_I2C_SWITCH != slave.switch_number:
- if not slave_switch:
- slave_switch = I2C_SLAVE_SWITCH
-
- # Set the switch value that should be written
- switch_value = 1 << slave.switch_number
-
- # Write new value to the switch
- control_object.i2c_write(slave_switch, switch_value, struct.pack('b', switch_value))
-
- # Read data from the switch, make sure write was successful
- read_data, = struct.unpack('b', control_object.i2c_read(slave_switch, switch_value, I2C_SWITCH_REGISTER_SIZE))
- if read_data != switch_value:
- raise I2CSlavesException("Switch writing has failed. Read data is different then expected %s != %s" % (
- read_data,
- switch_value))
+from hailo_platform.pyhailort.i2c_slaves import * # noqa F401
\ No newline at end of file
-from hailo_platform.drivers.hailort.pyhailort import (DvmTypes, PowerMeasurementTypes, # noqa F401
- SamplingPeriod, AveragingFactor,
- HailoPowerMeasurementUtils)
-
-""" Amount of time between each power measurement interval.
- The default values for provides by the sensor a new value every:
- 2 * sampling_period (1.1) * averaging_factor (256) [ms].
- Therefore we want it to be the period of time that the core will sleep between samples,
- plus a factor of 20 percent """
-DEFAULT_POWER_MEASUREMENT_DELAY_PERIOD_MS = int((HailoPowerMeasurementUtils.return_real_sampling_period(SamplingPeriod.PERIOD_1100us) / 1000.0 *
- HailoPowerMeasurementUtils.return_real_averaging_factor(AveragingFactor.AVERAGE_256) * 2) * 1.2)
\ No newline at end of file
+from hailo_platform.pyhailort.power_measurement import * # noqa F401
\ No newline at end of file
-import sys
-
-from hailo_platform.drivers.hailo_controller.hailo_control_protocol import BoardInformation, CoreInformation, HailoResetTypes, ExtendedDeviceInformation, HealthInformation
-
-from argparse import ArgumentTypeError
-import numpy
-import signal
-import time
-from hailo_platform.common.logger.logger import default_logger
-import gc
-import os
-
-import hailo_platform.drivers.hailort._pyhailort as _pyhailort
-from hailo_platform.drivers.hailort._pyhailort import (BootloaderVersion, TemperatureInfo, # noqa F401
- DvmTypes, PowerMeasurementTypes, # noqa F401
- PowerMeasurementData, NotificationId, # noqa F401
- OvercurrentAlertState,
- FormatOrder,
- AveragingFactor, SamplingPeriod,
- FormatType, WatchdogMode,
- MipiDataTypeRx, MipiPixelsPerClock,
- MipiClockSelection, MipiIspImageInOrder,
- MipiIspImageOutDataType, IspLightFrequency,
- BootSource, HailoSocketDefs, Endianness,
- MipiInputStreamParams, SensorConfigTypes,
- SensorConfigOpCode)
-
-BBOX_PARAMS = _pyhailort.HailoRTDefaults.BBOX_PARAMS()
-HAILO_DEFAULT_ETH_CONTROL_PORT = _pyhailort.HailoRTDefaults.HAILO_DEFAULT_ETH_CONTROL_PORT()
-INPUT_DATAFLOW_BASE_PORT = _pyhailort.HailoRTDefaults.DEVICE_BASE_INPUT_STREAM_PORT()
-OUTPUT_DATAFLOW_BASE_PORT = _pyhailort.HailoRTDefaults.DEVICE_BASE_OUTPUT_STREAM_PORT()
-PCIE_ANY_DOMAIN = _pyhailort.HailoRTDefaults.PCIE_ANY_DOMAIN()
-DEFAULT_VSTREAM_TIMEOUT_MS = 10000
-DEFAULT_VSTREAM_QUEUE_SIZE = 2
-
-class HailoSocket(object):
- MAX_UDP_PAYLOAD_SIZE = HailoSocketDefs.MAX_UDP_PAYLOAD_SIZE()
- MIN_UDP_PAYLOAD_SIZE = HailoSocketDefs.MIN_UDP_PAYLOAD_SIZE()
- MAX_UDP_PADDED_PAYLOAD_SIZE = HailoSocketDefs.MAX_UDP_PADDED_PAYLOAD_SIZE()
- MIN_UDP_PADDED_PAYLOAD_SIZE = HailoSocketDefs.MIN_UDP_PADDED_PAYLOAD_SIZE()
- MAX_ALIGNED_UDP_PAYLOAD_SIZE_RTP = HailoSocketDefs.MAX_ALIGNED_UDP_PAYLOAD_SIZE_RTP()
-
-
-class HailoRTException(Exception):
- pass
-
-class UdpRecvError(HailoRTException):
- pass
-
-class InvalidProtocolVersionException(HailoRTException):
- pass
-
-class HailoRTFirmwareControlFailedException(HailoRTException):
- pass
-
-class HailoRTInvalidFrameException(HailoRTException):
- pass
-
-class HailoRTUnsupportedOpcodeException(HailoRTException):
- pass
-
-class HailoRTTimeout(HailoRTException):
- pass
-
-class HailoRTStreamAborted(HailoRTException):
- pass
-
-class HailoRTInvalidOperationException(HailoRTException):
- pass
-
-class HailoRTInvalidArgumentException(HailoRTException):
- pass
-
-class HailoRTNotFoundException(HailoRTException):
- pass
-
-class HailoRTInvalidHEFException(HailoRTException):
- pass
-
-class HailoRTEthException(HailoRTException):
- pass
-
-class HailoRTPCIeDriverException(HailoRTException):
- pass
-
-class HailoRTNetworkGroupNotActivatedException(HailoRTException):
- pass
-
-class HailoStatusInvalidValueException(Exception):
- pass
-
-class ExceptionWrapper(object):
- def __enter__(self):
- pass
-
- def __exit__(self, exception_type, value, traceback):
- if value is not None:
- if exception_type is _pyhailort.HailoRTStatusException:
- self._raise_indicative_status_exception(int(value.args[0]))
- else:
- raise
-
- def _raise_indicative_status_exception(self, error_code):
- string_error_code = get_status_message(error_code)
- if string_error_code == "HAILO_ETH_RECV_FAILURE":
- raise UdpRecvError("Failed to receive data")
- if string_error_code == "HAILO_UNSUPPORTED_CONTROL_PROTOCOL_VERSION":
- raise InvalidProtocolVersionException("HailoRT has failed because an invalid protocol version was received from device")
- if string_error_code == "HAILO_FW_CONTROL_FAILURE":
- raise HailoRTFirmwareControlFailedException("libhailort control operation failed")
- if string_error_code == "HAILO_UNSUPPORTED_OPCODE":
- raise HailoRTUnsupportedOpcodeException("HailoRT has failed because an unsupported opcode was sent to device")
- if string_error_code == "HAILO_INVALID_FRAME":
- raise HailoRTInvalidFrameException("An invalid frame was received")
- if string_error_code == "HAILO_TIMEOUT":
- raise HailoRTTimeout("Received a timeout - hailort has failed because a timeout had occurred")
- if string_error_code == "HAILO_STREAM_ABORTED":
- raise HailoRTStreamAborted("Stream aborted due to an external event")
-
- if string_error_code == "HAILO_INVALID_OPERATION":
- raise HailoRTInvalidOperationException("Invalid operation. See hailort.log for more information")
- if string_error_code == "HAILO_INVALID_ARGUMENT":
- raise HailoRTInvalidArgumentException("Invalid argument. See hailort.log for more information")
- if string_error_code == "HAILO_NOT_FOUND":
- raise HailoRTNotFoundException("Item not found. See hailort.log for more information")
-
- if string_error_code == "HAILO_INVALID_HEF":
- raise HailoRTInvalidHEFException("Invalid HEF. See hailort.log for more information")
-
- if string_error_code == "HAILO_ETH_FAILURE":
- raise HailoRTEthException("Ethernet failure. See hailort.log for more information")
- if string_error_code == "HAILO_PCIE_DRIVER_FAIL":
- raise HailoRTPCIeDriverException("PCIe driver failure. run 'dmesg | grep hailo' for more information")
-
- if string_error_code == "HAILO_NETWORK_GROUP_NOT_ACTIVATED":
- raise HailoRTNetworkGroupNotActivatedException("Network group is not activated")
- else:
- raise HailoRTException("libhailort failed with error: {} ({})".format(error_code, string_error_code))
-
-def get_status_message(status_code):
- status_str = _pyhailort.get_status_message(status_code)
- if status_str == "":
- raise HailoStatusInvalidValueException("Value {} is not a valid status".format(status_code))
- return status_str
-
-class Control(object):
- class Type(object):
- PCIE = 0
- ETH = 1
-
- def __init__(self, control_type, address, port, pcie_device_info=None, response_timeout_seconds=10,
- max_number_of_attempts=3):
- self.device = None
- self.control_type = control_type
- self._eth_address = address
- self._eth_port = port
- self._eth_response_timeout_milliseconds = int(response_timeout_seconds * 1000)
- self._eth_max_number_of_attempts = max_number_of_attempts
- self._pcie_device_info = pcie_device_info
-
- if sys.platform != "win32":
- signal.pthread_sigmask(signal.SIG_BLOCK, [signal.SIGWINCH])
-
- def ensure_device(method):
- def _ensure_device(self, *args, **kw):
- if self.device is not None:
- return method(self, *args, **kw)
-
- with ExceptionWrapper():
- if self.control_type == Control.Type.PCIE:
- self.device = _pyhailort.create_pcie_device(self._pcie_device_info)
- _pyhailort.identify(self.device)
- elif self.control_type == Control.Type.ETH:
- self.device = _pyhailort.create_eth_device(self._eth_address, len(self._eth_address), self._eth_port,
- self._eth_response_timeout_milliseconds, self._eth_max_number_of_attempts)
- else:
- raise HailoRTException("Unsupported control type")
- try:
- result = method(self, *args, **kw)
- finally:
- if self.device is not None:
- with ExceptionWrapper():
- _pyhailort.release_device(self.device)
- self.device = None
-
- return result
- return _ensure_device
-
- def set_device(self, device_object):
- if device_object is None:
- self.device = None
- else:
- self.device = device_object.device
-
- @ensure_device
- def identify(self):
- with ExceptionWrapper():
- response = _pyhailort.identify(self.device)
- board_information = BoardInformation(response.protocol_version, response.fw_version.major,
- response.fw_version.minor, response.fw_version.revision, response.logger_version,
- response.board_name, response.is_release, int(response.device_architecture), response.serial_number,
- response.part_number, response.product_name)
- return board_information
-
- @ensure_device
- def core_identify(self):
- with ExceptionWrapper():
- response = _pyhailort.core_identify(self.device)
- core_information = CoreInformation(response.fw_version.major, response.fw_version.minor,
- response.fw_version.revision, response.is_release)
- return core_information
-
- @ensure_device
- def set_fw_logger(self, level, interface_mask):
- with ExceptionWrapper():
- return _pyhailort.set_fw_logger(self.device, level, interface_mask)
-
- @ensure_device
- def set_throttling_state(self, should_activate):
- with ExceptionWrapper():
- return _pyhailort.set_throttling_state(self.device, should_activate)
-
- @ensure_device
- def get_throttling_state(self):
- with ExceptionWrapper():
- return _pyhailort.get_throttling_state(self.device)
-
- @ensure_device
- def _set_overcurrent_state(self, should_activate):
- with ExceptionWrapper():
- return _pyhailort._set_overcurrent_state(self.device, should_activate)
-
- @ensure_device
- def _get_overcurrent_state(self):
- with ExceptionWrapper():
- return _pyhailort._get_overcurrent_state(self.device)
-
- @ensure_device
- def read_memory(self, address, length):
- with ExceptionWrapper():
- return _pyhailort.read_memory(self.device, int(address), int(length))
-
- @ensure_device
- def write_memory(self, address, data):
- with ExceptionWrapper():
- return _pyhailort.write_memory(self.device, int(address), data, len(data))
-
- @ensure_device
- def configure_device_from_hef(self, hef, configure_params_by_name={}):
- with ExceptionWrapper():
- return _pyhailort.configure_device_from_hef(self.device, hef._hef, configure_params_by_name)
-
- @ensure_device
- def _create_c_i2c_slave(self, pythonic_slave):
- c_slave = _pyhailort.I2CSlaveConfig()
- c_slave.endianness = pythonic_slave.endianness
- c_slave.slave_address = pythonic_slave.slave_address
- c_slave.register_address_size = pythonic_slave.register_address_size
- c_slave.bus_index = pythonic_slave.bus_index
- return c_slave
-
- @ensure_device
- def i2c_write(self, pythonic_slave, register_address, data):
- c_slave = self._create_c_i2c_slave(pythonic_slave)
- with ExceptionWrapper():
- return _pyhailort.i2c_write(self.device, c_slave, register_address, data, len(data))
-
- @ensure_device
- def i2c_read(self, pythonic_slave, register_address, data_length):
- c_slave = self._create_c_i2c_slave(pythonic_slave)
- with ExceptionWrapper():
- return _pyhailort.i2c_read(self.device, c_slave, register_address, data_length)
-
- @ensure_device
- def power_measurement(self, dvm, measurement_type):
- with ExceptionWrapper():
- return _pyhailort.power_measurement(self.device, dvm, measurement_type)
-
- @ensure_device
- def start_power_measurement(self, delay_milliseconds, averaging_factor, sampling_period):
- with ExceptionWrapper():
- return _pyhailort.start_power_measurement(self.device, delay_milliseconds,
- averaging_factor, sampling_period)
-
- @ensure_device
- def set_power_measurement(self, index, dvm, measurement_type):
- with ExceptionWrapper():
- return _pyhailort.set_power_measurement(self.device, index, dvm, measurement_type)
-
- @ensure_device
- def get_power_measurement(self, index, should_clear):
- with ExceptionWrapper():
- return _pyhailort.get_power_measurement(self.device, index, should_clear)
-
- @ensure_device
- def stop_power_measurement(self):
- with ExceptionWrapper():
- return _pyhailort.stop_power_measurement(self.device)
-
- @ensure_device
- def examine_user_config(self):
- with ExceptionWrapper():
- return _pyhailort.examine_user_config(self.device)
-
- @ensure_device
- def read_user_config(self):
- with ExceptionWrapper():
- return _pyhailort.read_user_config(self.device)
-
- @ensure_device
- def write_user_config(self, data):
- with ExceptionWrapper():
- return _pyhailort.write_user_config(self.device, data)
-
- @ensure_device
- def erase_user_config(self):
- with ExceptionWrapper():
- return _pyhailort.erase_user_config(self.device)
-
- @ensure_device
- def read_board_config(self):
- with ExceptionWrapper():
- return _pyhailort.read_board_config(self.device)
-
- @ensure_device
- def write_board_config(self, data):
- with ExceptionWrapper():
- return _pyhailort.write_board_config(self.device, data)
-
- @ensure_device
- def reset(self, reset_type):
- map_mode = {
- HailoResetTypes.CHIP : _pyhailort.ResetDeviceMode.CHIP,
- HailoResetTypes.NN_CORE : _pyhailort.ResetDeviceMode.NN_CORE,
- HailoResetTypes.SOFT : _pyhailort.ResetDeviceMode.SOFT,
- HailoResetTypes.FORCED_SOFT : _pyhailort.ResetDeviceMode.FORCED_SOFT
- }
-
- mode = map_mode[reset_type]
- with ExceptionWrapper():
- return _pyhailort.reset(self.device, mode)
-
- @ensure_device
- def sensor_store_config(self, section_index, reset_data_size, sensor_type, config_file_path, config_height, config_width,
- config_fps, config_name):
- with ExceptionWrapper():
- return _pyhailort.sensor_store_config(self.device, section_index, reset_data_size, sensor_type, config_file_path,
- config_height, config_width, config_fps, config_name)
-
- @ensure_device
- def store_isp_config(self, reset_config_size, config_height, config_width, config_fps, isp_static_config_file_path,
- isp_runtime_config_file_path, config_name):
- with ExceptionWrapper():
- return _pyhailort.store_isp_config(self.device, reset_config_size, config_height, config_width, config_fps,
- isp_static_config_file_path, isp_runtime_config_file_path, config_name)
-
- @ensure_device
- def sensor_get_sections_info(self):
- with ExceptionWrapper():
- return _pyhailort.sensor_get_sections_info(self.device)
-
- @ensure_device
- def sensor_set_i2c_bus_index(self, sensor_type, bus_index):
- with ExceptionWrapper():
- return _pyhailort.sensor_set_i2c_bus_index(self.device, sensor_type, bus_index)
-
- @ensure_device
- def sensor_load_and_start_config(self, section_index):
- with ExceptionWrapper():
- return _pyhailort.sensor_load_and_start_config(self.device, section_index)
-
- @ensure_device
- def sensor_reset(self, section_index):
- with ExceptionWrapper():
- return _pyhailort.sensor_reset(self.device, section_index)
-
- @ensure_device
- def sensor_set_generic_i2c_slave(self, slave_address, register_address_size, bus_index, should_hold_bus, endianness):
- with ExceptionWrapper():
- return _pyhailort.sensor_set_generic_i2c_slave(self.device, slave_address, register_address_size, bus_index, should_hold_bus, endianness)
-
- @ensure_device
- def firmware_update(self, firmware_binary, should_reset):
- with ExceptionWrapper():
- return _pyhailort.firmware_update(self.device, firmware_binary, len(firmware_binary), should_reset)
-
- @ensure_device
- def second_stage_update(self, second_stage_binary):
- with ExceptionWrapper():
- return _pyhailort.second_stage_update(self.device, second_stage_binary, len(second_stage_binary))
-
- @ensure_device
- def set_pause_frames(self, rx_pause_frames_enable):
- with ExceptionWrapper():
- return _pyhailort.set_pause_frames(self.device, rx_pause_frames_enable)
-
- @ensure_device
- def wd_enable(self, cpu_id):
- with ExceptionWrapper():
- return _pyhailort.wd_enable(self.device, cpu_id)
-
- @ensure_device
- def wd_disable(self, cpu_id):
- with ExceptionWrapper():
- return _pyhailort.wd_disable(self.device, cpu_id)
-
- @ensure_device
- def wd_config(self, cpu_id, wd_cycles, wd_mode):
- with ExceptionWrapper():
- return _pyhailort.wd_config(self.device, cpu_id, wd_cycles, WatchdogMode(wd_mode))
-
- @ensure_device
- def previous_system_state(self, cpu_id):
- with ExceptionWrapper():
- return _pyhailort.previous_system_state(self.device, cpu_id)
-
- @ensure_device
- def get_chip_temperature(self):
- with ExceptionWrapper():
- return _pyhailort.get_chip_temperature(self.device)
-
- @ensure_device
- def get_extended_device_information(self):
- with ExceptionWrapper():
- response = _pyhailort.get_extended_device_information(self.device)
- device_information = ExtendedDeviceInformation(response.neural_network_core_clock_rate,
- response.supported_features, response.boot_source, response.lcs, response.soc_id, response.eth_mac_address , response.unit_level_tracking_id, response.soc_pm_values)
- return device_information
-
- @ensure_device
- def _get_health_information(self):
- with ExceptionWrapper():
- response = _pyhailort._get_health_information(self.device)
- health_information = HealthInformation(response.overcurrent_protection_active, response.current_overcurrent_zone, response.red_overcurrent_threshold,
- response.orange_overcurrent_threshold, response.temperature_throttling_active, response.current_temperature_zone, response.current_temperature_throttling_level,
- response.temperature_throttling_levels, response.orange_temperature_threshold, response.orange_hysteresis_temperature_threshold,
- response.red_temperature_threshold, response.red_hysteresis_temperature_threshold)
- return health_information
-
- @ensure_device
- def set_notification_callback(self, callback_func, notification_id, opaque):
- with ExceptionWrapper():
- _pyhailort.set_notification_callback(self.device, callback_func, notification_id, opaque)
-
- @ensure_device
- def remove_notification_callback(self, notification_id):
- with ExceptionWrapper():
- _pyhailort.remove_notification_callback(self.device, notification_id)
-
- @ensure_device
- def test_chip_memories(self):
- """
- Test chip memories using smart BIST mechanism.
- """
- with ExceptionWrapper():
- return _pyhailort.test_chip_memories(self.device)
-
- @ensure_device
- def _get_device_handle(self):
- return self.device
-
-class HailoUdpScan(object):
- def __init__(self):
- self._logger = default_logger()
- with ExceptionWrapper():
- self._scan = _pyhailort.UdpScan()
-
- def scan_devices(self, interface_name, timeout_seconds=3):
- self._logger.info('Scanning over interface {iface}'.format(iface=interface_name))
- timeout_milliseconds = int(timeout_seconds * 1000)
- device_ip_addresses = self._scan.scan_devices(interface_name, timeout_milliseconds)
- for ip in device_ip_addresses:
- self._logger.debug("Found board at: {}".format(ip))
- return device_ip_addresses
-
-
-class TrafficControl(object):
- def __init__(self, ip, port, rate_bytes_per_sec):
- if sys.platform != 'linux':
- raise HailoRTInvalidOperationException('TrafficControl is supported only on UNIX os')
- with ExceptionWrapper():
- self._tc_util = _pyhailort.TrafficControlUtil(ip, port, int(rate_bytes_per_sec))
-
- def set_rate_limit(self):
- self._tc_util.set_rate_limit()
-
- def reset_rate_limit(self):
- self._tc_util.reset_rate_limit()
-
- def get_interface_name(ip):
- "get the interface corresponding to the given ip"
- with ExceptionWrapper():
- return _pyhailort.TrafficControlUtil.get_interface_name(ip)
-
-
-class ConfigureParams(object):
-
- @staticmethod
- def create_from_hef(hef, interface):
- """Create configure params from HEF. These params affects the HEF configuration into a device.
-
- Args:
- hef (:class:`HEF`): The HEF to create the parameters from.
- interface (:class:`HailoStreamInterface`): The stream_interface to create stream_params for.
-
- Returns:
- dict: The created stream params. The keys are the network_group names in the HEF. The values are default params, which can be changed.
- """
- with ExceptionWrapper():
- return hef._hef.create_configure_params(interface)
-
- @staticmethod
- def create_mipi_inputs_from_hef(hef, output_interface, mipi_rx_id=0, data_type=MipiDataTypeRx.RAW_8,
- img_width_pixels=1920, img_height_pixels=1080,
- pixels_per_clock=MipiPixelsPerClock.PIXELS_PER_CLOCK_4, number_of_lanes=2,
- clock_selection=MipiClockSelection.SELECTION_AUTOMATIC, data_rate=260, virtual_channel_index=0,
- isp_enable=False, isp_img_in_order=MipiIspImageInOrder.GR_FIRST,
- isp_img_out_data_type=MipiIspImageOutDataType.RGB_888, isp_crop_enable=False,
- isp_crop_output_width_pixels=1920, isp_crop_output_height_pixels=1080,
- isp_crop_output_width_start_offset_pixels=0, isp_crop_output_height_start_offset_pixels=0,
- isp_test_pattern_enable=True, isp_configuration_bypass=False,
- isp_run_time_ae_enable=True, isp_run_time_awb_enable=True, isp_run_time_adt_enable=True,
- isp_run_time_af_enable=False, isp_run_time_calculations_interval_ms=0,
- isp_light_frequency=IspLightFrequency.LIGHT_FREQ_50_HZ):
- """Create configure params from HEF. These params affects the HEF configuration into a device.
-
- .. attention:: The ISP and its features are not officially supported yet.
-
- Args:
- hef (:class:`HEF`): The HEF to create the parameters from.
- output_interface (:class:`HailoStreamInterface`): The stream_interface to create output stream_params for.
- mipi_rx_id (int): Selection of which MIPI Rx device to use.
- data_type (:class:`~hailo_platform.drivers.hailort.pyhailort.MipiDataTypeRx`): The data type which will be passed over the MIPI.
- img_width_pixels (int): The width in pixels of the image that enter to the mipi CSI. The sensor output.
- When isp_enable and isp_crop_enable is false, is also the stream input.
- img_height_pixels (int): The height in pixels of the image that enter to the mipi CSI. The sensor output.
- When isp_enable and isp_crop_enable is false, is also the stream input.
- pixels_per_clock (:class:`~hailo_platform.drivers.hailort.pyhailort.MipiPixelsPerClock`): Number of pixels transmitted at each
- clock.
- number_of_lanes (int): Number of lanes to use.
- clock_selection (:class:`~hailo_platform.drivers.hailort.pyhailort.MipiClockSelection`): Selection of clock range that would be
- used. Setting :class:`~hailo_platform.drivers.hailort.pyhailort.MipiClockSelection.SELECTION_AUTOMATIC` means that the
- clock selection is calculated from the data rate.
- data_rate (int): Rate of the passed data (MHz).
- virtual_channel_index (int): The virtual channel index of the MIPI dphy.
- isp_enable (bool): Enable the ISP block in the MIPI dataflow. The ISP is not supported yet.
- isp_img_in_order (:class:`~hailo_platform.drivers.hailort.pyhailort.MipiIspImageInOrder`):
- The ISP Rx bayer pixel order. Only relevant when the ISP is enabled.
- isp_img_out_data_type (:class:`~hailo_platform.drivers.hailort.pyhailort.MipiIspImageOutDataType`):
- The data type that the mipi will take out. Only relevant when the ISP is enabled.
- isp_crop_enable (bool): Enable the crop feature in the ISP. Only relevant when the ISP is enabled.
- isp_crop_output_width_pixels (int): The width in pixels of the output window that the ISP take out. The stream input.
- Useful when isp_crop_enable is True. Only relevant when the ISP is enabled.
- isp_crop_output_height_pixels (int): The height in pixels of the output window that the ISP take out. The stream input.
- Useful when isp_crop_enable is True. Only relevant when the ISP is enabled.
- isp_crop_output_width_start_offset_pixels (int): The width start point of the output window that the ISP take out.
- Useful when isp_crop_enable is True. Only relevant when the ISP is enabled.
- isp_crop_output_height_start_offset_pixels (int): The height start point of the output window that the ISP take out.
- Useful when isp_crop_enable is True. Only relevant when the ISP is enabled.
- isp_test_pattern_enable (bool): Enable Test pattern from the ISP. Only relevant when the ISP is enabled.
- isp_configuration_bypass (bool): Don't load the ISP configuration file from the FLASH. Only relevant when the ISP is enabled.
- isp_run_time_ae_enable (bool): Enable the run-time Auto Exposure in the ISP. Only relevant when the ISP is enabled.
- isp_run_time_awb_enable (bool): Enable the run-time Auto White Balance in the ISP. Only relevant when the ISP is enabled.
- isp_run_time_adt_enable (bool): Enable the run-time Adaptive Function in the ISP. Only relevant when the ISP is enabled.
- isp_run_time_af_enable (bool): Enable the run-time Auto Focus in the ISP. Only relevant when the ISP is enabled.
- isp_run_time_calculations_interval_ms (int): Interval in milliseconds between ISP run time calculations. Only relevant when the ISP is enabled.
- isp_light_frequency (:class:`~hailo_platform.drivers.hailort.pyhailort.IspLightFrequency`):
- Selection of the light frequency. This parameter varies depending on the power grid of the country where
- the product is running. Only relevant when the ISP is enabled.
- Returns:
- dict: The created stream params. The keys are the network_group names in the HEF. The values are default params, which can be changed.
- """
-
- mipi_params = MipiInputStreamParams()
- mipi_params.mipi_rx_id = mipi_rx_id
- mipi_params.data_type = data_type
- mipi_params.isp_enable = isp_enable
- mipi_params.mipi_common_params.pixels_per_clock = pixels_per_clock
- mipi_params.mipi_common_params.number_of_lanes = number_of_lanes
- mipi_params.mipi_common_params.clock_selection = clock_selection
- mipi_params.mipi_common_params.virtual_channel_index = virtual_channel_index
- mipi_params.mipi_common_params.data_rate = data_rate
- mipi_params.mipi_common_params.img_width_pixels = img_width_pixels
- mipi_params.mipi_common_params.img_height_pixels = img_height_pixels
- mipi_params.isp_params.img_in_order = isp_img_in_order
- mipi_params.isp_params.img_out_data_type = isp_img_out_data_type
- mipi_params.isp_params.crop_enable = isp_crop_enable
- mipi_params.isp_params.crop_output_width_pixels = isp_crop_output_width_pixels
- mipi_params.isp_params.crop_output_height_pixels = isp_crop_output_height_pixels
- mipi_params.isp_params.crop_output_width_start_offset_pixels = isp_crop_output_width_start_offset_pixels
- mipi_params.isp_params.crop_output_height_start_offset_pixels = isp_crop_output_height_start_offset_pixels
- mipi_params.isp_params.test_pattern_enable = isp_test_pattern_enable
- mipi_params.isp_params.configuration_bypass = isp_configuration_bypass
- mipi_params.isp_params.run_time_ae_enable = isp_run_time_ae_enable
- mipi_params.isp_params.run_time_awb_enable = isp_run_time_awb_enable
- mipi_params.isp_params.run_time_adt_enable = isp_run_time_adt_enable
- mipi_params.isp_params.run_time_af_enable = isp_run_time_af_enable
- mipi_params.isp_params.isp_run_time_calculations_interval_ms = isp_run_time_calculations_interval_ms
- mipi_params.isp_params.isp_light_frequency = isp_light_frequency
- with ExceptionWrapper():
- return hef._hef.create_configure_params_mipi_input(output_interface, mipi_params)
-
-def _get_name_as_str(name):
- return name if name is not None else ""
-
-class HEF(object):
- """Python representation of the Hailo Executable Format, which contains one or more compiled
- models.
- """
-
- def __init__(self, hef_source):
- """Constructor for the HEF class.
-
- Args:
- hef_source (str or bytes): The source from which the HEF object will be created. If the
- source type is `str`, it is treated as a path to an hef file. If the source type is
- `bytes`, it is treated as a buffer. Any other type will raise a ValueError.
- """
-
- with ExceptionWrapper():
- if isinstance(hef_source, str):
- self._hef = _pyhailort.Hef.create_from_file(hef_source)
- self._path = hef_source
- elif isinstance(hef_source, bytes):
- self._hef = _pyhailort.Hef.create_from_buffer(hef_source)
- self._path = None
- else:
- raise ValueError("HEF can only be created from a file path (str) or a buffer (bytes)")
- self._sorted_output_names = {}
-
- def get_networks_names(self, network_group_name=None):
- """Gets the names of all networks in a specific network group.
-
- Args:
- network_group_name (str, optional): The name of the network group to access. If not given, first network_group is addressed.
-
- Returns:
- list of str: The names of the networks.
- """
- name = _get_name_as_str(network_group_name)
- with ExceptionWrapper():
- return self._hef.get_networks_names(name)
-
- @property
- def path(self):
- """HEF file path."""
- return self._path
-
- def get_network_group_names(self):
- """Get the names of the network groups in this HEF."""
- with ExceptionWrapper():
- return self._hef.get_network_group_names()
-
- def get_network_groups_infos(self):
- """Get information about the network groups in this HEF."""
- with ExceptionWrapper():
- return self._hef.get_network_groups_infos()
-
- def get_input_vstream_infos(self, name=None):
- """Get input vstreams information.
-
- Args:
- name (str, optional): The name of the network or network_group to access. In case network_group name is given,
- Address all networks of the given network_group. In case not given, first network_group is addressed.
-
- Returns:
- list of :obj:`hailo_platform.drivers.hailort._pyhailort.VStreamInfo`: with all the information objects of all input vstreams.
- """
- name = _get_name_as_str(name)
- return self._hef.get_input_vstream_infos(name)
-
- def get_output_vstream_infos(self, name=None):
- """Get output vstreams information.
-
- Args:
- name (str, optional): The name of the network or network_group to access. In case network_group name is given,
- Address all networks of the given network_group. In case not given, first network_group is addressed.
-
- Returns:
- list of :obj:`hailo_platform.drivers.hailort._pyhailort.VStreamInfo`: with all the information objects of all output vstreams
- """
- name = _get_name_as_str(name)
- return self._hef.get_output_vstream_infos(name)
-
- def get_all_vstream_infos(self, name=None):
- """Get input and output vstreams information.
-
- Args:
- name (str, optional): The name of the network or network_group to access. In case network_group name is given,
- Address all networks of the given network_group. In case not given, first network_group is addressed.
-
- Returns:
- list of :obj:`hailo_platform.drivers.hailort._pyhailort.VStreamInfo`: with all the information objects of all input and output vstreams
- """
- name = _get_name_as_str(name)
- return self._hef.get_all_vstream_infos(name)
-
- def get_input_stream_infos(self, name=None):
- """Get the input low-level streams information.
-
- Args:
- name (str, optional): The name of the network or network_group to access. In case network_group name is given,
- Address all networks of the given network_group. In case not given, first network_group is addressed.
-
- Returns:
- List of :obj:`hailo_platform.drivers.hailort._pyhailort.StreamInfo`: with information objects
- of all input low-level streams.
- """
- name = _get_name_as_str(name)
- return self._hef.get_input_stream_infos(name)
-
-
- def get_output_stream_infos(self, name=None):
- """Get the output low-level streams information of a specific network group.
-
- Args:
- name (str, optional): The name of the network or network_group to access. In case network_group name is given,
- Address all networks of the given network_group. In case not given, first network_group is addressed.
-
- Returns:
- List of :obj:`hailo_platform.drivers.hailort._pyhailort.StreamInfo`: with information objects
- of all output low-level streams.
- """
- name = _get_name_as_str(name)
- return self._hef.get_output_stream_infos(name)
-
- def get_all_stream_infos(self, name=None):
- """Get input and output streams information of a specific network group.
-
- Args:
- name (str, optional): The name of the network or network_group to access. In case network_group name is given,
- Address all networks of the given network_group. In case not given, first network_group is addressed.
-
- Returns:
- list of :obj:`hailo_platform.drivers.hailort._pyhailort.StreamInfo`: with all the information objects of all input and output streams
- """
- name = _get_name_as_str(name)
- return self._hef.get_all_stream_infos(name)
-
- def get_sorted_output_names(self, network_group_name=None):
- """Get the names of the outputs in a network group. The order of names is determined by
- the SDK. If the network group is not given, the first one is used.
- """
- if network_group_name is None:
- network_group_name = self.get_network_group_names()[0]
-
- if network_group_name not in self._sorted_output_names:
- with ExceptionWrapper():
- self._sorted_output_names[network_group_name] = self._hef.get_sorted_output_names(network_group_name)
- return self._sorted_output_names[network_group_name]
-
- def bottleneck_fps(self, network_group_name=None):
- if network_group_name is None:
- network_group_name = self.get_network_group_names()[0]
- with ExceptionWrapper():
- bottleneck_fps = self._hef.get_bottleneck_fps(network_group_name)
- if bottleneck_fps == 0:
- raise HailoRTException("bottleneck_fps is zero")
- return bottleneck_fps
-
- def get_udp_rates_dict(self, fps, max_supported_rate_bytes, network_group_name=None):
- if network_group_name is None:
- network_group_name = self.get_network_group_names()[0]
- with ExceptionWrapper():
- return self._hef.get_udp_rates_dict(network_group_name, fps, int(max_supported_rate_bytes))
-
- def get_vstream_name_from_original_name(self, original_name, network_group_name=None):
- """Get vstream name from original layer name for a specific network group.
-
- Args:
- original_name (str): The original layer name.
- network_group_name (str, optional): The name of the network group to access. If not given, first network_group is addressed.
-
- Returns:
- str: the matching vstream name for the provided original name.
- """
- if network_group_name is None:
- network_group_name = self.get_network_group_names()[0]
- with ExceptionWrapper():
- return self._hef.get_vstream_name_from_original_name(original_name, network_group_name)
-
- def get_original_names_from_vstream_name(self, vstream_name, network_group_name=None):
- """Get original names list from vstream name for a specific network group.
-
- Args:
- vstream_name (str): The stream name.
- network_group_name (str, optional): The name of the network group to access. If not given, first network_group is addressed.
-
- Returns:
- list of str: all the matching original layers names for the provided vstream name.
- """
- if network_group_name is None:
- network_group_name = self.get_network_group_names()[0]
- with ExceptionWrapper():
- return self._hef.get_original_names_from_vstream_name(vstream_name, network_group_name)
-
- def get_vstream_names_from_stream_name(self, stream_name, network_group_name=None):
- """Get vstream names list from their underlying stream name for a specific network group.
-
- Args:
- stream_name (str): The underlying stream name.
- network_group_name (str, optional): The name of the network group to access. If not given, first network_group is addressed.
-
- Returns:
- list of str: All the matching vstream names for the provided stream name.
- """
- if network_group_name is None:
- network_group_name = self.get_network_group_names()[0]
- with ExceptionWrapper():
- return self._hef.get_vstream_names_from_stream_name(stream_name, network_group_name)
-
- def get_stream_names_from_vstream_name(self, vstream_name, network_group_name=None):
- """Get stream name from vstream name for a specific network group.
-
- Args:
- vstream_name (str): The name of the vstreams.
- network_group_name (str, optional): The name of the network group to access. If not given, first network_group is addressed.
-
- Returns:
- list of str: All the underlying streams names for the provided vstream name.
- """
- if network_group_name is None:
- network_group_name = self.get_network_group_names()[0]
- with ExceptionWrapper():
- return self._hef.get_stream_names_from_vstream_name(vstream_name, network_group_name)
-
-
-class ConfiguredNetwork(object):
- """Represents a network group loaded to the device."""
-
- def __init__(self, configured_network, target, hef):
- self._configured_network = configured_network
- self._target = target
- self._hef = hef
-
- def get_networks_names(self):
- return self._hef.get_networks_names(self.name)
-
- def activate(self, network_group_params=None):
- """Activate this network group in order to infer data through it.
-
- Args:
- network_group_params (:obj:`hailo_platform.drivers.hailort._pyhailort.ActivateNetworkGroupParams`, optional):
- Network group activation params. If not given, default params will be applied,
-
- Returns:
- :class:`ActivatedNetworkContextManager`: Context manager that returns the activated
- network group.
- """
- network_group_params = network_group_params or self.create_params()
-
- with ExceptionWrapper():
- return ActivatedNetworkContextManager(self,
- self._configured_network.activate(network_group_params),
- self._target, self._hef)
-
- def wait_for_activation(self, timeout_ms=None):
- """Block until activated, or until ``timeout_ms`` is passed.
-
- Args:
- timeout_ms (int, optional): Timeout value in milliseconds to wait for activation.
- Defaults to ``HAILO_INFINITE``.
-
- Raises:
- :class:`HailoRTTimeout`: In case of timeout.
- """
- MAX_INT = 0x7fffffff
- with ExceptionWrapper():
- if timeout_ms is None:
- timeout_ms = MAX_INT
- return self._configured_network.wait_for_activation(timeout_ms)
-
- @staticmethod
- def create_params():
- """Create activation params for network_group.
-
- Returns:
- :obj:`hailo_platform.drivers.hailort._pyhailort.ActivateNetworkGroupParams`.
- """
- return _pyhailort.ActivateNetworkGroupParams.default()
-
- @property
- def name(self):
- return self._configured_network.get_name()
-
- def get_output_shapes(self):
- name_to_shape = {vstream_info.name : vstream_info.shape for vstream_info in self.get_output_vstream_infos()}
- results = []
- for name in self.get_sorted_output_names():
- results.append(name_to_shape[name])
- return tuple(results)
-
- def get_sorted_output_names(self):
- return self._hef.get_sorted_output_names(self.name)
-
- def get_input_vstream_infos(self, network_name=None):
- """Get input vstreams information.
-
- Args:
- network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
-
- Returns:
- list of :obj:`hailo_platform.drivers.hailort._pyhailort.VStreamInfo`: with all the information objects of all input vstreams
- """
-
- name = network_name if network_name is not None else self.name
- return self._hef.get_input_vstream_infos(name)
-
- def get_output_vstream_infos(self, network_name=None):
- """Get output vstreams information.
-
- Args:
- network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
-
- Returns:
- list of :obj:`hailo_platform.drivers.hailort._pyhailort.VStreamInfo`: with all the information objects of all output vstreams
- """
-
- name = network_name if network_name is not None else self.name
- return self._hef.get_output_vstream_infos(name)
-
- def get_all_vstream_infos(self, network_name=None):
- """Get input and output vstreams information.
-
- Args:
- network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
-
- Returns:
- list of :obj:`hailo_platform.drivers.hailort._pyhailort.VStreamInfo`: with all the information objects of all input and output vstreams
- """
-
- name = network_name if network_name is not None else self.name
- return self._hef.get_all_vstream_infos(name)
-
- def get_input_stream_infos(self, network_name=None):
- """Get the input low-level streams information of a specific network group.
-
- Args:
- network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
-
- Returns:
- List of :obj:`hailo_platform.drivers.hailort._pyhailort.StreamInfo`: with information objects
- of all input low-level streams.
- """
-
- name = network_name if network_name is not None else self.name
- return self._hef.get_input_stream_infos(name)
-
- def get_output_stream_infos(self, network_name=None):
- """Get the output low-level streams information of a specific network group.
-
- Args:
- network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
-
- Returns:
- List of :obj:`hailo_platform.drivers.hailort._pyhailort.StreamInfo`: with information objects
- of all output low-level streams.
- """
-
- name = network_name if network_name is not None else self.name
- return self._hef.get_output_stream_infos(name)
-
- def get_all_stream_infos(self, network_name=None):
- """Get input and output streams information of a specific network group.
-
- Args:
- network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
-
- Returns:
- list of :obj:`hailo_platform.drivers.hailort._pyhailort.StreamInfo`: with all the information objects of all input and output streams
- """
-
- name = network_name if network_name is not None else self.name
- return self._hef.get_all_stream_infos(name)
-
- def get_udp_rates_dict(self, fps, max_supported_rate_bytes):
- with ExceptionWrapper():
- return self._configured_network.get_udp_rates_dict(int(fps), int(max_supported_rate_bytes))
-
- def _create_input_vstreams(self, input_vstreams_params):
- return self._configured_network.InputVStreams(input_vstreams_params)
-
- def _create_output_vstreams(self, output_vstreams_params):
- return self._configured_network.OutputVStreams(output_vstreams_params)
-
- def get_stream_names_from_vstream_name(self, vstream_name):
- """Get stream name from vstream name for a specific network group.
-
- Args:
- vstream_name (str): The name of the vstreams.
-
- Returns:
- list of str: All the underlying streams names for the provided vstream name.
- """
- with ExceptionWrapper():
- return self._hef.get_stream_names_from_vstream_name(vstream_name, self.name)
-
- def get_vstream_names_from_stream_name(self, stream_name):
- """Get vstream names list from their underlying stream name for a specific network group.
-
- Args:
- stream_name (str): The underlying stream name.
-
- Returns:
- list of str: All the matching vstream names for the provided stream name.
- """
- with ExceptionWrapper():
- return self._hef.get_vstream_names_from_stream_name(stream_name, self.name)
-
-
-class ActivatedNetworkContextManager(object):
- """A context manager that returns the activated network group upon enter."""
-
- def __init__(self, configured_network, activated_network, target, hef):
- self._configured_network = configured_network
- self._activated_network = activated_network
- self._target = target
- self._hef = hef
-
- def __enter__(self):
- with ExceptionWrapper():
- activated_network_group = ActivatedNetwork(self._configured_network, self._activated_network.__enter__(), self._target,
- self._hef)
- return activated_network_group
-
- def __exit__(self, *args):
- self._activated_network.__exit__(*args)
-
-
-class ActivatedNetwork(object):
- """The network group that is currently activated for inference."""
-
- def __init__(self, configured_network, activated_network, target, hef):
- self._configured_network = configured_network
- self._activated_network = activated_network
- self._target = target
- self._hef = hef
- self._last_number_of_invalid_frames_read = 0
-
- @property
- def target(self):
- return self._target
-
- @property
- def name(self):
- return self._configured_network.name
-
- def get_number_of_invalid_frames(self, clear=True):
- """Returns number of invalid frames.
-
- Args:
- clear (bool): If set, the returned value will be the number of invalid frames read since the last call to this function.
-
- Returns:
- int: Number of invalid frames.
- """
- total_invalid_frames_count = self._activated_network.get_invalid_frames_count()
- if clear:
- value = total_invalid_frames_count - self._last_number_of_invalid_frames_read
- self._last_number_of_invalid_frames_read = total_invalid_frames_count
- return value if clear else total_invalid_frames_count
-
- def validate_all_frames_are_valid(self):
- """Validates that all of the frames so far are valid (no invalid frames)."""
- number_of_invalid_frames = self.get_number_of_invalid_frames()
- if number_of_invalid_frames != 0:
- raise HailoRTException("There are {} invalid frames.".format(number_of_invalid_frames))
-
- def get_sorted_output_names(self):
- return self._hef.get_sorted_output_names(self.name)
-
- def _get_intermediate_buffer(self, src_context_index, src_stream_index):
- with ExceptionWrapper():
- return self._activated_network.get_intermediate_buffer(src_context_index, src_stream_index)
-
-
-class InferVStreams(object):
- """Pipeline that allows to call blocking inference, to be used as a context manager."""
-
- def __init__(self, configured_net_group, input_vstreams_params, output_vstreams_params,
- tf_nms_format=False):
- """Constructor for the InferVStreams class.
-
- Args:
- configured_net_group (:class:`ConfiguredNetwork`): The configured network group for
- which the pipeline is created.
- input_vstreams_params (dict from str to :class:`InputVStreamParams`): Params for the
- input vstreams in the pipeline. Only members of this dict will take part in the
- inference.
- output_vstreams_params (dict from str to :class:`OutputVStreamParams`): Params for the
- output vstreams in the pipeline. Only members of this dict will take part in the
- inference.
- tf_nms_format (bool, optional): indicates whether the returned nms outputs should be in
- Hailo format or TensorFlow format. Default is False (using Hailo format).
-
- * Hailo format -- list of :obj:`numpy.ndarray`. Each element represents the
- detections (bboxes) for the class, and its shape is
- ``[number_of_detections, BBOX_PARAMS]``
- * TensorFlow format -- :obj:`numpy.ndarray` of shape
- ``[class_count, BBOX_PARAMS, detections_count]`` padded with empty bboxes.
- """
-
- self._logger = default_logger()
- self._configured_net_group = configured_net_group
- self._net_group_name = configured_net_group.name
- self._input_vstreams_params = input_vstreams_params
- self._output_vstreams_params = output_vstreams_params
- self._tf_nms_format = tf_nms_format
- self._total_time = None
- self._hw_time = None
- self._network_name_to_outputs = InferVStreams._get_network_to_outputs_mapping(configured_net_group)
- self._input_name_to_network_name = InferVStreams._get_input_name_to_network_mapping(configured_net_group)
-
- @staticmethod
- def _get_input_name_to_network_mapping(configured_net_group):
- input_name_to_network_mapping = {}
- for network_name in configured_net_group.get_networks_names():
- for input_vstream_info in configured_net_group.get_input_vstream_infos(network_name):
- input_name_to_network_mapping[input_vstream_info.name] = network_name
- return input_name_to_network_mapping
-
- @staticmethod
- def _get_network_to_outputs_mapping(configured_net_group):
- network_to_outputs_mapping = {}
- for network_name in configured_net_group.get_networks_names():
- network_to_outputs_mapping[network_name] = set()
- for output_vstream_info in configured_net_group.get_output_vstream_infos(network_name):
- network_to_outputs_mapping[network_name].add(output_vstream_info.name)
- return network_to_outputs_mapping
-
- def _make_output_buffers_and_infos(self, input_data, batch_size):
- output_buffers = {}
- output_buffers_info = {}
- already_seen_networks = set()
- for input_name in input_data.keys():
- network_name = self._input_name_to_network_name[input_name]
- if (network_name not in already_seen_networks) :
- already_seen_networks.add(network_name)
- for output_name in self._network_name_to_outputs[network_name]:
- output_buffers_info[output_name] = OutputLayerUtils(self._configured_net_group._hef, output_name, self._infer_pipeline,
- self._net_group_name)
- output_tensor_info = output_buffers_info[output_name].output_tensor_info
- shape, dtype = output_tensor_info
- output_buffers[output_name] = numpy.empty([batch_size] + list(shape), dtype=dtype)
- return output_buffers, output_buffers_info
-
- def __enter__(self):
- self._infer_pipeline = _pyhailort.InferVStreams(self._configured_net_group._configured_network,
- self._input_vstreams_params, self._output_vstreams_params)
- return self
-
- def infer(self, input_data):
- """Run inference on the hardware device.
-
- Args:
- input_data (dict of :obj:`numpy.ndarray`): Where the key is the name of the input_layer,
- and the value is the data to run inference on.
-
- Returns:
- dict: Output tensors of all output layers. The keys are outputs names and the values
- are output data tensors as :obj:`numpy.ndarray` (or list of :obj:`numpy.ndarray` in case of nms output and tf_nms_format=False).
- """
-
- time_before_infer_calcs = time.time()
- if not isinstance(input_data, dict):
- input_stream_infos = self._configured_net_group.get_input_stream_infos()
- if len(input_stream_infos) != 1:
- raise Exception("when there is more than one input, the input_data should be of type dict,"
- " mapping between each input_name, and his input_data tensor. number of inputs: {}".format(len(input_stream_infos)))
- input_data = {input_stream_infos[0].name : input_data}
-
- batch_size = InferVStreams._get_number_of_frames(input_data)
- output_buffers, output_buffers_info = self._make_output_buffers_and_infos(input_data, batch_size)
-
- for input_layer_name in input_data:
- # TODO: Remove cast after tests are updated and are working
- self._cast_input_data_if_needed(input_layer_name, input_data)
- self._validate_input_data_format_type(input_layer_name, input_data)
- self._make_c_contiguous_if_needed(input_layer_name, input_data)
-
- with ExceptionWrapper():
- time_before_infer = time.time()
- self._infer_pipeline.infer(input_data, output_buffers, batch_size)
- self._hw_time = time.time() - time_before_infer
-
- for name, result_array in output_buffers.items():
- is_nms = output_buffers_info[name].is_nms
- if not is_nms:
- continue
- nms_shape = output_buffers_info[name].vstream_info.nms_shape
- if self._tf_nms_format:
- shape = [batch_size] + output_buffers_info[name].old_nms_fomrat_shape
- output_dtype = output_buffers_info[name].output_dtype
- quantized_empty_bbox = output_buffers_info[name].quantized_empty_bbox
- flat_result_array = result_array.reshape(-1)
- output_buffers[name] = HailoRTTransformUtils.output_raw_buffer_to_nms_tf_format(flat_result_array, shape,
- output_dtype, quantized_empty_bbox)
- else:
- output_buffers[name] = HailoRTTransformUtils.output_raw_buffer_to_nms_format(result_array, nms_shape.number_of_classes)
-
- self._total_time = time.time() - time_before_infer_calcs
- return output_buffers
-
- def get_hw_time(self):
- """Get the hardware device operation time it took to run inference over the last batch.
-
- Returns:
- float: Time in seconds.
- """
- return self._hw_time
-
- def get_total_time(self):
- """Get the total time it took to run inference over the last batch.
-
- Returns:
- float: Time in seconds.
- """
- return self._total_time
-
- def _cast_input_data_if_needed(self, input_layer_name, input_data):
- input_dtype = input_data[input_layer_name].dtype
- with ExceptionWrapper():
- input_expected_dtype = self._infer_pipeline.get_host_dtype(input_layer_name)
- if input_dtype != input_expected_dtype:
-
- self._logger.warning("Given input data dtype ({}) is different than inferred dtype ({}). "
- "conversion for every frame will reduce performance".format(input_dtype,
- input_expected_dtype))
- input_data[input_layer_name] = input_data[input_layer_name].astype(input_expected_dtype)
-
- def _validate_input_data_format_type(self, input_layer_name, input_data):
- if input_layer_name not in self._input_vstreams_params:
- return
-
- input_data_format = self._input_vstreams_params[input_layer_name].user_buffer_format
- input_expected_item_size = _pyhailort.get_format_data_bytes(input_data_format)
- input_item_size = input_data[input_layer_name].dtype.itemsize
-
- # TODO: Add distinction between float32 and int32 and others
- if input_item_size != input_expected_item_size:
- raise HailoRTException("{} numpy array item size is {}, not {}".format(input_layer_name,
- input_item_size, input_expected_item_size))
-
- @staticmethod
- def _get_number_of_frames(input_data):
- # Checks that all the batch-sizes of the input_data are equals for all input layers
- if len(input_data) == 0:
- raise ValueError("Input_data can't be empty")
- batch_size_of_first_input = list(input_data.values())[0].shape[0]
- for name, input_data_tensor in input_data.items():
- if input_data_tensor.shape[0] != batch_size_of_first_input:
- raise ValueError(
- "The number of frames on all input_tensors should be equal! different sizes detected: {} != {}".format(
- batch_size_of_first_input, input_data_tensor.shape[0]))
- return batch_size_of_first_input
-
- def _make_c_contiguous_if_needed(self, input_layer_name, input_data):
- if not input_data[input_layer_name].flags.c_contiguous:
- self._logger.warning("Converting {} numpy array to be C_CONTIGUOUS".format(
- input_layer_name))
- input_data[input_layer_name] = numpy.asarray(input_data[input_layer_name], order='C')
-
- def __exit__(self, *args):
- self._infer_pipeline.release()
- return False
-
-
-class HailoRTTransformUtils(object):
- @staticmethod
- def get_dtype(data_bytes):
- """Get data type from the number of bytes."""
- if data_bytes == 1:
- return numpy.uint8
- elif data_bytes == 2:
- return numpy.uint16
- elif data_bytes == 4:
- return numpy.float32
- raise HailoRTException("unsupported data bytes value")
-
- @staticmethod
- def dequantize_output_buffer(src_buffer, dst_buffer, elements_count, quant_info):
- """De-quantize the data in input buffer `src_buffer` and output it to the buffer `dst_buffer`
-
- Args:
- src_buffer (:obj:`numpy.ndarray`): The input buffer containing the data to be de-quantized.
- The buffer's data type is the source data type.
- dst_buffer (:obj:`numpy.ndarray`): The buffer that will contain the de-quantized data.
- The buffer's data type is the destination data type.
- elements_count (int): The number of elements to de-quantize. This number must not exceed 'src_buffer' or 'dst_buffer' sizes.
- quant_info (:class:`~hailo_platform.drivers.hailort.pyhailort.QuantInfo`): The quantization info.
- """
- with ExceptionWrapper():
- src_format_type = HailoRTTransformUtils._get_format_type(src_buffer.dtype)
- dst_format_type = HailoRTTransformUtils._get_format_type(dst_buffer.dtype)
- _pyhailort.dequantize_output_buffer(src_buffer, dst_buffer, src_format_type, dst_format_type, elements_count, quant_info)
-
- @staticmethod
- def dequantize_output_buffer_in_place(raw_buffer, dst_dtype, elements_count, quant_info):
- """De-quantize the output buffer `raw_buffer` to data type `dst_dtype`.
-
- Args:
- raw_buffer (:obj:`numpy.ndarray`): The output buffer to be de-quantized. The buffer's data type is the source data type.
- dst_dtype (:obj:`numpy.dtype`): The data type to de-quantize `raw_buffer` to.
- elements_count (int): The number of elements to de-quantize. This number must not exceed 'raw_buffer' size.
- quant_info (:class:`~hailo_platform.drivers.hailort.pyhailort.QuantInfo`): The quantization info.
- """
- with ExceptionWrapper():
- src_format_type = HailoRTTransformUtils._get_format_type(raw_buffer.dtype)
- dst_format_type = HailoRTTransformUtils._get_format_type(dst_dtype)
- _pyhailort.dequantize_output_buffer_in_place(raw_buffer, src_format_type, dst_format_type, elements_count, quant_info)
-
- @staticmethod
- def quantize_input_buffer(src_buffer, dst_buffer, elements_count, quant_info):
- """Quantize the data in input buffer `src_buffer` and output it to the buffer `dst_buffer`
-
- Args:
- src_buffer (:obj:`numpy.ndarray`): The input buffer containing the data to be quantized.
- The buffer's data type is the source data type.
- dst_buffer (:obj:`numpy.ndarray`): The buffer that will contain the quantized data.
- The buffer's data type is the destination data type.
- elements_count (int): The number of elements to quantize. This number must not exceed 'src_buffer' or 'dst_buffer' sizes.
- quant_info (:class:`~hailo_platform.drivers.hailort.pyhailort.QuantInfo`): The quantization info.
- """
- with ExceptionWrapper():
- src_format_type = HailoRTTransformUtils._get_format_type(src_buffer.dtype)
- dst_format_type = HailoRTTransformUtils._get_format_type(dst_buffer.dtype)
- _pyhailort.quantize_input_buffer(src_buffer, dst_buffer, src_format_type, dst_format_type, elements_count, quant_info)
-
- @staticmethod
- def output_raw_buffer_to_nms_tf_format(raw_output_buffer, shape, dtype, quantized_empty_bbox):
- offset = 0
- # We create the tf_format buffer with reversed width/features for preformance optimization
- converted_output_buffer = numpy.empty([shape[0], shape[1], shape[3], shape[2]], dtype=dtype)
- for frame in range(converted_output_buffer.shape[0]):
- offset = frame * converted_output_buffer.shape[1] * (converted_output_buffer.shape[2] * converted_output_buffer.shape[3] + 1)
- HailoRTTransformUtils.output_raw_buffer_to_nms_tf_format_single_frame(raw_output_buffer, converted_output_buffer[frame],
- converted_output_buffer.shape[1], converted_output_buffer.shape[2], quantized_empty_bbox, offset)
- converted_output_buffer = numpy.swapaxes(converted_output_buffer, 2, 3)
- return converted_output_buffer
-
- @staticmethod
- def output_raw_buffer_to_nms_tf_format_single_frame(raw_output_buffer, converted_output_frame, number_of_classes,
- max_bboxes_per_class, quantized_empty_bbox, offset=0):
- for class_i in range(number_of_classes):
- class_bboxes_amount = int(raw_output_buffer[offset])
- offset += 1
- if 0 != class_bboxes_amount:
- converted_output_frame[class_i][ : class_bboxes_amount][:] = raw_output_buffer[offset : offset + (BBOX_PARAMS * class_bboxes_amount)].reshape(class_bboxes_amount, BBOX_PARAMS)
- offset += BBOX_PARAMS * class_bboxes_amount
- converted_output_frame[class_i][class_bboxes_amount : max_bboxes_per_class][:] = quantized_empty_bbox
-
- @staticmethod
- def output_raw_buffer_to_nms_format(raw_output_buffer, number_of_classes):
- converted_output_buffer = []
- for frame in raw_output_buffer:
- converted_output_buffer.append(HailoRTTransformUtils.output_raw_buffer_to_nms_format_single_frame(frame, number_of_classes))
- return converted_output_buffer
-
- @staticmethod
- def output_raw_buffer_to_nms_format_single_frame(raw_output_buffer, number_of_classes, offset=0):
- converted_output_frame = []
- for class_i in range(number_of_classes):
- class_bboxes_amount = int(raw_output_buffer[offset])
- offset += 1
- if class_bboxes_amount == 0:
- converted_output_frame.append(numpy.empty([0, BBOX_PARAMS]))
- else:
- converted_output_frame.append(raw_output_buffer[offset : offset + (BBOX_PARAMS * class_bboxes_amount)].reshape(
- class_bboxes_amount, BBOX_PARAMS))
- offset += BBOX_PARAMS * class_bboxes_amount
- return converted_output_frame
-
- @staticmethod
- def _get_format_type(dtype):
- if dtype == numpy.uint8:
- return FormatType.UINT8
- elif dtype == numpy.uint16:
- return FormatType.UINT16
- elif dtype == numpy.float32:
- return FormatType.FLOAT32
- raise HailoRTException("unsupported data type {}".format(dtype))
-
-class InternalEthernetDevice(object):
- def __init__(self, address, port, response_timeout_seconds=10, max_number_of_attempts=3):
- self.device = None
- self._address = address
- self._port = port
- self._response_timeout_milliseconds = int(response_timeout_seconds * 1000)
- self._max_number_of_attempts = max_number_of_attempts
- with ExceptionWrapper():
- self.device = _pyhailort.create_eth_device(self._address, len(self._address), self._port,
- self._response_timeout_milliseconds, self._max_number_of_attempts)
-
- def __del__(self):
- self.release()
-
- def release(self):
- if self.device is None:
- return
- with ExceptionWrapper():
- _pyhailort.release_device(self.device)
- self.device = None
-
-
-class PcieDeviceInfo(_pyhailort.PcieDeviceInfo):
- """Represents pcie device info, includeing domain, bus, device and function.
- """
-
- BOARD_LOCATION_HELP_STRING = 'Board location in the format of the command: "lspci -d 1e60: | cut -d\' \' -f1" ([<domain>]:<bus>:<device>.<func>). If not specified the first board is taken.'
-
- def __init__(self, bus, device, func, domain=None):
- super(PcieDeviceInfo, self).__init__()
- self.bus = bus
- self.device = device
- self.func = func
- if domain is None:
- self.domain = PCIE_ANY_DOMAIN
- else:
- self.domain = domain
-
- def __eq__(self, other):
- return (self.domain, self.bus, self.device, self.func) == (other.domain, other.bus, other.device, other.func)
-
- def __str__(self):
- with ExceptionWrapper():
- return super().__str__()
-
- def __repr__(self):
- return 'PcieDeviceInfo({})'.format(str(self))
-
- @classmethod
- def from_string(cls, board_location_str):
- """Parse pcie device info BDF from string. The format is [<domain>]:<bus>:<device>.<func>"""
- with ExceptionWrapper():
- device_info = _pyhailort.PcieDeviceInfo._parse(board_location_str)
- return PcieDeviceInfo(device_info.bus, device_info.device, device_info.func, device_info.domain)
-
- @classmethod
- def argument_type(cls, board_location_str):
- """PcieDeviceInfo Argument type for argparse parsers"""
- try:
- return cls.from_string(board_location_str)
- except HailoRTException:
- raise ArgumentTypeError('Invalid device info string, format is [<domain>]:<bus>:<device>.<func>')
-
-
-class InternalPcieDevice(object):
- def __init__(self, device_info=None, send_identify=True):
- self.device = None
- if device_info is None:
- device_info = InternalPcieDevice.scan_devices()[0]
- self._device_handle = None
- self._device_info = device_info
- with ExceptionWrapper():
- self.device = _pyhailort.create_pcie_device(self._device_info)
- self._device_handle = _pyhailort.get_hlpcie_device(self.device)
- if send_identify:
- _pyhailort.identify(self.device)
-
- def __del__(self):
- self.release()
-
- def release(self):
- if self.device is None:
- return
- with ExceptionWrapper():
- _pyhailort.release_device(self.device)
- self._device_handle = None
- self.device = None
-
- @staticmethod
- def scan_devices():
- with ExceptionWrapper():
- return [PcieDeviceInfo(dev_info.bus, dev_info.device, dev_info.func, dev_info.domain)
- for dev_info in _pyhailort.scan_pcie_devices()]
-
- def create_debug_log(self):
- return PcieDebugLog(self)
-
- def write_memory(self, address, data):
- with ExceptionWrapper():
- _pyhailort.direct_write_memory(self.device, address, data)
-
- def read_memory(self, address, size):
- with ExceptionWrapper():
- return _pyhailort.direct_read_memory(self.device, address, size)
-
-
-class PcieDebugLog(object):
- def __init__(self, pci_device):
- self._pcie_device = pci_device
-
- def read(self, count, cpu_id):
- with ExceptionWrapper():
- return _pyhailort.read_log(self._pcie_device.device, count, cpu_id)
-
-
-class HailoPowerMeasurementUtils(object):
- @staticmethod
- def return_real_sampling_period(sampling_period):
- """Get a sampling period from the enum."""
- SamplingPeriodDictionary = dict([
- (SamplingPeriod.PERIOD_140us, 140),
- (SamplingPeriod.PERIOD_204us, 204),
- (SamplingPeriod.PERIOD_332us, 332),
- (SamplingPeriod.PERIOD_588us, 588),
- (SamplingPeriod.PERIOD_1100us, 1100),
- (SamplingPeriod.PERIOD_2116us, 2116),
- (SamplingPeriod.PERIOD_4156us, 4156),
- (SamplingPeriod.PERIOD_8244us, 8244),
- ])
- return SamplingPeriodDictionary[sampling_period]
-
- @staticmethod
- def return_real_averaging_factor(averaging_factor):
- """Get an averaging factor from the enum."""
- AveragingFactorDictionary = dict([
- (AveragingFactor.AVERAGE_1, 1),
- (AveragingFactor.AVERAGE_4, 4),
- (AveragingFactor.AVERAGE_16, 16),
- (AveragingFactor.AVERAGE_64, 64),
- (AveragingFactor.AVERAGE_128, 128),
- (AveragingFactor.AVERAGE_256, 256),
- (AveragingFactor.AVERAGE_512, 512),
- (AveragingFactor.AVERAGE_1024, 1024),
- ])
- return AveragingFactorDictionary[averaging_factor]
-
-
-class HailoPowerMode(_pyhailort.PowerMode):
- pass
-
-class HailoStreamInterface(_pyhailort.StreamInterface):
- pass
-
-class HailoStreamDirection(_pyhailort.StreamDirection):
- pass
-
-class HailoCpuId(_pyhailort.CpuId):
- pass
-
-class HailoFormatFlags(_pyhailort.FormatFlags):
- pass
-
-
-class VDevice(object):
- """Hailo virtual device representation."""
-
- def __init__(
- self,
- params=None, device_infos=None):
-
- """Create the Hailo virtual device object.
-
- Args:
- params (:obj:`hailo_platform.drivers.hailort.pyhailort.VDeviceParams`, optional): VDevice params, call
- :func:`VDevice.create_params` to get default params. Excludes 'device_infos'.
- device_infos (list of :obj:`hailo_platform.drivers.hailort.pyhailort.PcieDeviceInfo`, optional): pcie devices infos to create VDevice from,
- call :func:`PcieDevice.scan_devices` to get list of all available devices. Excludes 'params'.
- """
- gc.collect()
- self._id = "VDevice"
- self._params = params
- self._device_infos = device_infos
- if self._device_infos is not None:
- if self._params is not None:
- raise HailoRTException("VDevice can be created from params or device_infos. Both parameters was passed to the c'tor")
- self._vdevice = None
- self._loaded_network_groups = []
- if self._vdevice is None:
- self._open_vdevice()
-
- self._creation_pid = os.getpid()
-
- def _open_vdevice(self):
- if self._device_infos is not None:
- with ExceptionWrapper():
- self._vdevice = _pyhailort.VDevice.create_from_infos(self._device_infos)
- else:
- if self._params is None:
- self._params = VDevice.create_params()
- with ExceptionWrapper():
- self._vdevice = _pyhailort.VDevice.create(self._params)
-
- def __enter__(self):
- if self._vdevice is None:
- self._open_vdevice()
- return self
-
- def release(self):
- if self._vdevice is not None:
- self._vdevice.release()
- self._vdevice = None
-
- def __exit__(self, *args):
- self.release()
- return False
-
- def __del__(self):
- self.release()
-
- @staticmethod
- def create_params():
- with ExceptionWrapper():
- return _pyhailort.VDeviceParams.default()
-
- def configure(self, hef, configure_params_by_name={}):
- """Configures target vdevice from HEF object.
-
- Args:
- hef (:class:`~hailo_platform.drivers.hailort.pyhailort.HEF`): HEF to configure the vdevice from
- configure_params_by_name (dict, optional): Maps between each net_group_name to configure_params. If not provided, default params will be applied
- """
- if self._creation_pid != os.getpid():
- raise HailoRTException("VDevice can only be configured from the process it was created in.")
- with ExceptionWrapper():
- configured_apps = self._vdevice.configure(hef._hef, configure_params_by_name)
- configured_networks = [ConfiguredNetwork(configured_app, self, hef) for configured_app in configured_apps]
- self._loaded_network_groups.extend(configured_networks)
- return configured_networks
-
- def get_physical_devices(self):
- """Gets the underlying physical devices.
-
- Return:
- list of :obj:`~hailo_platform.drivers.hw_object.PcieDevice`: The underlying physical devices.
- """
- with ExceptionWrapper():
- phys_dev_infos = self._vdevice.get_physical_devices_infos()
- pythonic_dev_infos = [PcieDeviceInfo(dev_info.bus, dev_info.device, dev_info.func, dev_info.domain)
- for dev_info in phys_dev_infos]
-
- from hailo_platform.drivers.hw_object import PcieDevice
- return [PcieDevice(info) for info in pythonic_dev_infos]
-
- def get_physical_devices_infos(self):
- """Gets the physical devices infos.
-
- Return:
- list of :obj:`~hailo_platform.drivers.hailort.pyhailort.PcieDeviceInfo`: The underlying physical devices infos.
- """
- with ExceptionWrapper():
- return self._vdevice.get_physical_devices_infos()
-
-
-class InputVStreamParams(object):
- """Parameters of an input virtual stream (host to device)."""
-
- @staticmethod
- def make(configured_network, quantized=True, format_type=None, timeout_ms=None, queue_size=None, network_name=None):
- """Create input virtual stream params from a configured network group. These params determine the format of the
- data that will be fed into the network group.
-
- Args:
- configured_network (:class:`ConfiguredNetwork`): The configured network group for which
- the params are created.
- quantized (bool): Whether the data fed into the chip is already quantized. True means
- the data is already quantized. False means it's HailoRT's responsibility to quantize
- (scale) the data. Defaults to True.
- format_type (:class:`~hailo_platform.drivers.hailort.pyhailort.FormatType`): The
- default format type of the data for all input virtual streams. If quantized is False,
- the default is :attr:`~hailo_platform.drivers.hailort.pyhailort.FormatType.FLOAT32`. Otherwise,
- the default is :attr:`~hailo_platform.drivers.hailort.pyhailort.FormatType.AUTO`,
- which means the data is fed in the same format expected by the device (usually
- uint8).
- timeout_ms (int): The default timeout in milliseconds for all input virtual streams.
- Defaults to DEFAULT_VSTREAM_TIMEOUT_MS. In case of timeout, :class:`HailoRTTimeout` will be raised.
- queue_size (int): The pipeline queue size. Defaults to DEFAULT_VSTREAM_QUEUE_SIZE.
- network_name (str): Network name of the requested virtual stream params.
- If not passed, all the networks in the network group will be addressed.
-
- Returns:
- dict: The created virtual streams params. The keys are the vstreams names. The values are the
- params.
- """
- if format_type is None:
- if not quantized:
- format_type = FormatType.FLOAT32
- else:
- format_type = FormatType.AUTO
- if timeout_ms is None:
- timeout_ms = DEFAULT_VSTREAM_TIMEOUT_MS
- if queue_size is None:
- queue_size = DEFAULT_VSTREAM_QUEUE_SIZE
- name = network_name if network_name is not None else configured_network.name
- with ExceptionWrapper():
- return configured_network._hef._hef.get_input_vstreams_params(name, quantized,
- format_type, timeout_ms, queue_size)
-
- @staticmethod
- def make_from_network_group(configured_network, quantized=True, format_type=None, timeout_ms=None, queue_size=None, network_name=None):
- """Create input virtual stream params from a configured network group. These params determine the format of the
- data that will be fed into the network group.
-
- Args:
- configured_network (:class:`ConfiguredNetwork`): The configured network group for which
- the params are created.
- quantized (bool): Whether the data fed into the chip is already quantized. True means
- the data is already quantized. False means it's HailoRT's responsibility to quantize
- (scale) the data. Defaults to True.
- format_type (:class:`~hailo_platform.drivers.hailort.pyhailort.FormatType`): The
- default format type of the data for all input virtual streams. If quantized is False,
- the default is :attr:`~hailo_platform.drivers.hailort.pyhailort.FormatType.FLOAT32`. Otherwise,
- the default is :attr:`~hailo_platform.drivers.hailort.pyhailort.FormatType.AUTO`,
- which means the data is fed in the same format expected by the device (usually
- uint8).
- timeout_ms (int): The default timeout in milliseconds for all input virtual streams.
- Defaults to DEFAULT_VSTREAM_TIMEOUT_MS. In case of timeout, :class:`HailoRTTimeout` will be raised.
- queue_size (int): The pipeline queue size. Defaults to DEFAULT_VSTREAM_QUEUE_SIZE.
- network_name (str): Network name of the requested virtual stream params.
- If not passed, all the networks in the network group will be addressed.
-
- Returns:
- dict: The created virtual streams params. The keys are the vstreams names. The values are the
- params.
- """
- return InputVStreamParams.make(configured_network, quantized, format_type, timeout_ms, queue_size, network_name)
-
-
-class OutputVStreamParams(object):
- """Parameters of an output virtual stream (device to host)."""
-
- @staticmethod
- def make(configured_network, quantized=True, format_type=None, timeout_ms=None, queue_size=None, network_name=None):
- """Create output virtual stream params from a configured network group. These params determine the format of the
- data that will be fed into the network group.
-
- Args:
- configured_network (:class:`ConfiguredNetwork`): The configured network group for which
- the params are created.
- quantized (bool): Whether the data fed into the chip is already quantized. True means
- the data is already quantized. False means it's HailoRT's responsibility to quantize
- (scale) the data. Defaults to True.
- format_type (:class:`~hailo_platform.drivers.hailort.pyhailort.FormatType`): The
- default format type of the data for all output virtual streams. If quantized is False,
- the default is :attr:`~hailo_platform.drivers.hailort.pyhailort.FormatType.FLOAT32`. Otherwise,
- the default is :attr:`~hailo_platform.drivers.hailort.pyhailort.FormatType.AUTO`,
- which means the data is fed in the same format expected by the device (usually
- uint8).
- timeout_ms (int): The default timeout in milliseconds for all output virtual streams.
- Defaults to DEFAULT_VSTREAM_TIMEOUT_MS. In case of timeout, :class:`HailoRTTimeout` will be raised.
- queue_size (int): The pipeline queue size. Defaults to DEFAULT_VSTREAM_QUEUE_SIZE.
- network_name (str): Network name of the requested virtual stream params.
- If not passed, all the networks in the network group will be addressed.
-
- Returns:
- dict: The created virtual streams params. The keys are the vstreams names. The values are the
- params.
- """
- if format_type is None:
- if not quantized:
- format_type = FormatType.FLOAT32
- else:
- format_type = FormatType.AUTO
- if timeout_ms is None:
- timeout_ms = DEFAULT_VSTREAM_TIMEOUT_MS
- if queue_size is None:
- queue_size = DEFAULT_VSTREAM_QUEUE_SIZE
- name = network_name if network_name is not None else configured_network.name
- with ExceptionWrapper():
- return configured_network._hef._hef.get_output_vstreams_params(name, quantized,
- format_type, timeout_ms, queue_size)
-
- @staticmethod
- def make_from_network_group(configured_network, quantized=True, format_type=None, timeout_ms=None, queue_size=None, network_name=None):
- """Create output virtual stream params from a configured network group. These params determine the format of the
- data that will be fed into the network group.
-
- Args:
- configured_network (:class:`ConfiguredNetwork`): The configured network group for which
- the params are created.
- quantized (bool): Whether the data fed into the chip is already quantized. True means
- the data is already quantized. False means it's HailoRT's responsibility to quantize
- (scale) the data. Defaults to True.
- format_type (:class:`~hailo_platform.drivers.hailort.pyhailort.FormatType`): The
- default format type of the data for all output virtual streams. If quantized is False,
- the default is :attr:`~hailo_platform.drivers.hailort.pyhailort.FormatType.FLOAT32`. Otherwise,
- the default is :attr:`~hailo_platform.drivers.hailort.pyhailort.FormatType.AUTO`,
- which means the data is fed in the same format expected by the device (usually
- uint8).
- timeout_ms (int): The default timeout in milliseconds for all output virtual streams.
- Defaults to DEFAULT_VSTREAM_TIMEOUT_MS. In case of timeout, :class:`HailoRTTimeout` will be raised.
- queue_size (int): The pipeline queue size. Defaults to DEFAULT_VSTREAM_QUEUE_SIZE.
- network_name (str): Network name of the requested virtual stream params.
- If not passed, all the networks in the network group will be addressed.
-
- Returns:
- dict: The created virtual streams params. The keys are the vstreams names. The values are the
- params.
- """
- return OutputVStreamParams.make(configured_network, quantized, format_type, timeout_ms, queue_size, network_name)
-
- @staticmethod
- def make_groups(configured_network, quantized=True, format_type=None, timeout_ms=None, queue_size=None):
- """Create output virtual stream params from a configured network group. These params determine the format of the
- data that will be fed into the network group. The params groups are splitted with respect to their underlying streams for multi process usges.
-
- Args:
- configured_network (:class:`ConfiguredNetwork`): The configured network group for which
- the params are created.
- quantized (bool): Whether the data fed into the chip is already quantized. True means
- the data is already quantized. False means it's HailoRT's responsibility to quantize
- (scale) the data. Defaults to True.
- format_type (:class:`~hailo_platform.drivers.hailort.pyhailort.FormatType`): The
- default format type of the data for all output virtual streams. If quantized is False,
- the default is :attr:`~hailo_platform.drivers.hailort.pyhailort.FormatType.FLOAT32`. Otherwise,
- the default is :attr:`~hailo_platform.drivers.hailort.pyhailort.FormatType.AUTO`,
- which means the data is fed in the same format expected by the device (usually
- uint8).
- timeout_ms (int): The default timeout in milliseconds for all output virtual streams.
- Defaults to DEFAULT_VSTREAM_TIMEOUT_MS. In case of timeout, :class:`HailoRTTimeout` will be raised.
- queue_size (int): The pipeline queue size. Defaults to DEFAULT_VSTREAM_QUEUE_SIZE.
-
- Returns:
- list of dicts: Each element in the list represent a group of params, where the keys are the vstreams names, and the values are the
- params. The params groups are splitted with respect to their underlying streams for multi process usges.
- """
- all_params = OutputVStreamParams.make(configured_network, quantized=quantized, format_type=format_type, timeout_ms=timeout_ms, queue_size=queue_size)
- low_level_streams_names = [stream_info.name for stream_info in configured_network.get_output_stream_infos()]
- stream_name_to_vstream_names = {stream_name: configured_network.get_vstream_names_from_stream_name(stream_name) for stream_name in low_level_streams_names}
- results = []
- for low_level_stream_name, vstream_names in stream_name_to_vstream_names.items():
- params_group = {}
- for vstream_name in vstream_names:
- # Vstreams that were already seen should not be added to another params_group
- if all_params[vstream_name] is not None:
- params_group[vstream_name] = all_params[vstream_name]
- all_params[vstream_name] = None
- if 0 < len(params_group):
- results.append(params_group)
- return results
-
-
-class InputVStream(object):
- """Represents a single virtual stream in the host to device direction."""
-
- def __init__(self, send_object):
- self._send_object = send_object
- self._input_dtype = self._send_object.dtype
-
- @property
- def shape(self):
- return self._send_object.shape
-
- @property
- def dtype(self):
- return self._send_object.dtype
-
- @property
- def name(self):
- return self._send_object.info.name
-
- @property
- def network_name(self):
- return self._send_object.info.network_name
-
- def send(self, input_data):
- """Send frames to inference.
-
- Args:
- input_data (:obj:`numpy.ndarray`): Data to run inference on.
- """
-
- if input_data.dtype != self._input_dtype:
- input_data = input_data.astype(self._input_dtype)
-
- if not input_data.flags.c_contiguous:
- logger = default_logger()
- logger.warning("Warning - Converting input numpy array to be C_CONTIGUOUS")
- input_data = numpy.asarray(input_data, order='C')
-
- batch_number = 0
- batch_size = 1
- while batch_number < input_data.shape[0]:
- data = input_data[batch_number:batch_number + batch_size]
- with ExceptionWrapper():
- self._send_object.send(data)
- batch_number += batch_size
-
- def flush(self):
- """Blocks until there are no buffers in the input VStream pipeline."""
- with ExceptionWrapper():
- self._send_object.flush()
-
- @property
- def info(self):
- with ExceptionWrapper():
- return self._send_object.info
-
-class InputVStreams(object):
- """Input vstreams pipelines that allows to send data, to be used as a context manager."""
-
- def __init__(self, configured_network, input_vstreams_params):
- """Constructor for the InputVStreams class.
-
- Args:
- configured_network (:class:`ConfiguredNetwork`): The configured network group for which the pipeline is created.
- input_vstreams_params (dict from str to :class:`InputVStreamParams`): Params for the input vstreams in the pipeline.
- """
- self._configured_network = configured_network
- self._input_vstreams_params = input_vstreams_params
- self._vstreams = {}
-
- def __enter__(self):
- self._input_vstreams_holder = self._configured_network._create_input_vstreams(self._input_vstreams_params)
- self._input_vstreams_holder.__enter__()
- for name, vstream in self._input_vstreams_holder.get_all_inputs().items():
- self._vstreams[name] = InputVStream(vstream)
- return self
-
- def get(self, name=None):
- """Return a single input vstream by its name.
-
- Args:
- name (str): The vstream name. If name=None and there is a single input vstream, that single (:class:`InputVStream`) will be returned.
- Otherwise, if name=None and there are multiple input vstreams, an exception will be thrown.
-
- Returns:
- :class:`InputVStream`: The (:class:`InputVStream`) that corresponds to the given name.
- """
- if name is None:
- if len(self._vstreams) != 1:
- raise HailoRTException("There is no single input vStream. You must give a name")
- name = list(self._vstreams.keys())[0]
- return self._vstreams[name]
-
- def clear(self):
- """Clears the vstreams' pipeline buffers."""
- with ExceptionWrapper():
- self._input_vstreams_holder.clear()
-
- def __exit__(self, *args):
- self._input_vstreams_holder.__exit__(*args)
- return False
-
- def __iter__(self):
- return iter(self._vstreams.values())
-
-class OutputLayerUtils(object):
- def __init__(self, hef, vstream_name, pipeline, net_group_name=""):
- self._hef = hef
- self._net_group_name = net_group_name
- self._vstream_info = self._get_vstream_info(vstream_name)
-
- if isinstance(pipeline, (_pyhailort.InferVStreams)):
- # TODO: HRT-5754 - Save user buffer instead of dtype and flags.
- self._output_dtype = pipeline.get_host_dtype(vstream_name)
- self._output_shape = pipeline.get_shape(vstream_name)
- self._output_flags = pipeline.get_user_buffer_format(vstream_name).flags
- else:
- self._output_dtype = pipeline.dtype
- self._output_shape = pipeline.shape
- self._output_flags = pipeline.get_user_buffer_format().flags
-
- self._is_nms = (self._vstream_info.format.order == FormatOrder.HAILO_NMS)
- if self._is_nms:
- self._quantized_empty_bbox = numpy.asarray([0] * BBOX_PARAMS, dtype=self._output_dtype)
- if not (self._output_flags & _pyhailort.FormatFlags.QUANTIZED):
- HailoRTTransformUtils.dequantize_output_buffer_in_place(self._quantized_empty_bbox, self._output_dtype,
- BBOX_PARAMS, self._vstream_info.quant_info)
-
- @property
- def output_dtype(self):
- return self._output_dtype
-
- @property
- def output_shape(self):
- return self._output_shape
-
- @property
- def vstream_info(self):
- return self._vstream_info
-
- @property
- def output_tensor_info(self):
- return self.output_shape, self.output_dtype
-
- @property
- def is_nms(self):
- return self._is_nms
-
- @property
- def quantized_empty_bbox(self):
- return self._quantized_empty_bbox
-
- def _get_vstream_info(self, name):
- output_vstream_infos = self._hef.get_output_vstream_infos(self._net_group_name)
- for info in output_vstream_infos:
- if info.name == name:
- return info
- raise HailoRTException("No vstream matches the given name {}".format(name))
-
- @property
- def old_nms_fomrat_shape(self):
- nms_shape = self._vstream_info.nms_shape
- return [nms_shape.number_of_classes, BBOX_PARAMS,
- nms_shape.max_bboxes_per_class]
-
-class OutputVStream(object):
- """Represents a single output virtual stream in the device to host direction."""
-
- def __init__(self, configured_network, recv_object, name, tf_nms_format=False, net_group_name=""):
- self._recv_object = recv_object
- self._output_layer_utils = OutputLayerUtils(configured_network._hef, name, self._recv_object, net_group_name)
- self._output_dtype = self._output_layer_utils.output_dtype
- self._vstream_info = self._output_layer_utils._vstream_info
- self._output_tensor_info = self._output_layer_utils.output_tensor_info
- self._is_nms = self._output_layer_utils.is_nms
- if self._is_nms:
- self._quantized_empty_bbox = self._output_layer_utils.quantized_empty_bbox
- self._tf_nms_format = tf_nms_format
-
- @property
- def shape(self):
- return self._recv_object.shape
-
- @property
- def dtype(self):
- return self._recv_object.dtype
-
- @property
- def name(self):
- return self._vstream_info.name
-
- @property
- def network_name(self):
- return self._vstream_info.network_name
-
- def recv(self):
- """Receive frames after inference.
-
- Returns:
- :obj:`numpy.ndarray`: The output of the inference for a single frame. The returned
- tensor does not include the batch dimension.
- In case of nms output and tf_nms_format=False, returns list of :obj:`numpy.ndarray`.
- """
- result_array = None
- with ExceptionWrapper():
- result_array = self._recv_object.recv()
-
- if self._is_nms:
- nms_shape = self._vstream_info.nms_shape
- if self._tf_nms_format:
- nms_results_tesnor = result_array
- # We create the tf_format buffer with reversed width/features for preformance optimization
- shape = self._output_layer_utils.old_nms_fomrat_shape
- result_array = numpy.empty([shape[0], shape[2], shape[1]], dtype=self._output_dtype)
- HailoRTTransformUtils.output_raw_buffer_to_nms_tf_format_single_frame(nms_results_tesnor, result_array,
- nms_shape.number_of_classes,
- nms_shape.max_bboxes_per_class, self._quantized_empty_bbox)
- result_array = numpy.swapaxes(result_array, 1, 2)
- else:
- result_array = HailoRTTransformUtils.output_raw_buffer_to_nms_format_single_frame(result_array,
- nms_shape.number_of_classes)
- return result_array
-
- @property
- def info(self):
- with ExceptionWrapper():
- return self._recv_object.info
-
-class OutputVStreams(object):
- """Output virtual streams pipelines that allows to receive data, to be used as a context manager."""
-
- def __init__(self, configured_network, output_vstreams_params, tf_nms_format=False):
- """Constructor for the OutputVStreams class.
-
- Args:
- configured_network (:class:`ConfiguredNetwork`): The configured network group for which
- the pipeline is created.
- output_vstreams_params (dict from str to :class:`OutputVStreamParams`): Params for the
- output vstreams in the pipeline.
- tf_nms_format (bool, optional): indicates whether the returned nms outputs should be in
- Hailo format or TensorFlow format. Default is False (using Hailo format).
-
- * Hailo format -- list of :obj:`numpy.ndarray`. Each element represents th
- detections (bboxes) for the class, and its shape is
- ``[number_of_detections, BBOX_PARAMS]``
- * TensorFlow format -- :obj:`numpy.ndarray` of shape
- ``[class_count, BBOX_PARAMS, detections_count]`` padded with empty bboxes.
- """
- self._configured_network = configured_network
- self._net_group_name = configured_network.name
- self._output_vstreams_params = output_vstreams_params
- self._output_tensor_info = {}
- self._tf_nms_format = tf_nms_format
- self._vstreams = {}
-
- def __enter__(self):
- self._output_vstreams_holder = self._configured_network._create_output_vstreams(self._output_vstreams_params)
- self._output_vstreams_holder.__enter__()
- for name, vstream in self._output_vstreams_holder.get_all_outputs().items():
- self._vstreams[name] = OutputVStream(self._configured_network, vstream, name,
- tf_nms_format=self._tf_nms_format, net_group_name=self._net_group_name)
- return self
-
- def get(self, name=None):
- """Return a single output vstream by its name.
-
- Args:
- name (str): The vstream name. If name=None and there is a single output vstream, that single (:class:`OutputVStream`) will be returned.
- Otherwise, if name=None and there are multiple output vstreams, an exception will be thrown.
-
- Returns:
- :class:`OutputVStream`: The (:class:`OutputVStream`) that corresponds to the given name.
- """
- if name is None:
- if len(self._vstreams) != 1:
- raise HailoRTException("There is no single output vStream. You must give a name")
- name = list(self._vstreams.keys())[0]
- return self._vstreams[name]
-
- def clear(self):
- """Clears the vstreams' pipeline buffers."""
- with ExceptionWrapper():
- self._output_vstreams_holder.clear()
-
- def __exit__(self, *args):
- self._output_vstreams_holder.__exit__(*args)
- return False
-
- def __iter__(self):
- return iter(self._vstreams.values())
+from hailo_platform.pyhailort.pyhailort import * # noqa F401
-#!/usr/bin/env python
-
-"""Hailo hardware API"""
-from __future__ import division
-
-import gc
-import os
-
-from contextlib import contextmanager
-
-from hailo_platform.drivers.control_object import UdpHcpControl, PcieHcpControl
-from hailo_platform.common.compatibility import ensure_str
-from hailo_platform.common.targets.inference_targets import InferenceTargets, InferenceObject, InferenceTargetException
-from hailo_platform.common.logger.logger import default_logger
-from hailo_platform.drivers.hailo_controller.hailo_control_protocol import BoardInformation
-
-from hailo_platform.drivers.hailort.pyhailort import ConfiguredNetwork, InternalEthernetDevice, InternalPcieDevice, HailoRTTransformUtils, HailoUdpScan, HailoRTException
-
-
-class HailoHWObjectException(InferenceTargetException):
- """Raised in any error related to Hailo hardware."""
- pass
-
-
-class HailoHWObject(InferenceObject):
- """Abstract Hailo hardware device representation."""
-
- IS_NUMERIC = True
-
- def __init__(self):
- """Create the Hailo hardware object."""
- super(HailoHWObject, self).__init__()
- self._last_interact_time = None
- self._total_time = None
- self._id = None
- self._hw_arch = None
- self._logger = default_logger()
- self._debug = False
- self._is_device_used = False
- self._hef_loaded = False
-
- @property
- def device_id(self):
- """Getter for the device_id.
-
- Returns:
- str: A string ID of the device. BDF for PCIe devices, MAC address for Ethernet devices, "Core" for core devices.
- """
- return self._id
-
- @property
- def sorted_output_layer_names(self):
- """Getter for the property sorted_output_names.
-
- Returns:
- list of str: Sorted list of the output layer names.
- """
- if len(self._loaded_network_groups) != 1:
- raise HailoHWObjectException("Access to sorted_output_layer_names is only allowed when there is a single loaded network group")
- return self._loaded_network_groups[0].get_sorted_output_names()
-
- @contextmanager
- def use_device(self, *args, **kwargs):
- """A context manager that wraps the usage of the device (deprecated)."""
- self._is_device_used = True
- yield
- self._is_device_used = False
-
- def get_output_device_layer_to_original_layer_map(self):
- """Get a mapping between the device outputs to the layers' names they represent.
-
- Returns:
- dict: Keys are device output names and values are lists of layers' names.
- """
- if len(self._loaded_network_groups) != 1:
- raise HailoHWObjectException("Access to layer names is only allowed when there is a single loaded network group")
- return {stream_info.name : self._loaded_network_groups[0].get_vstream_names_from_stream_name(stream_info.name)
- for stream_info in self.get_output_stream_infos()}
-
- def get_original_layer_to_device_layer_map(self):
- """Get a mapping between the layer names and the device outputs that contain them.
-
- Returns:
- dict: Keys are the names of the layers and values are device outputs names.
- """
- if len(self._loaded_network_groups) != 1:
- raise HailoHWObjectException("Access to layer names is only allowed when there is a single loaded network group")
- return {vstream_info.name : self._loaded_network_groups[0].get_stream_names_from_vstream_name(vstream_info.name)
- for vstream_info in self.get_output_vstream_infos()}
-
- @property
- def device_input_layers(self):
- """Get a list of the names of the device's inputs."""
- return [layer.name for layer in self.get_input_stream_infos()]
-
- @property
- def device_output_layers(self):
- """Get a list of the names of the device's outputs."""
- return [layer.name for layer in self.get_output_stream_infos()]
-
- def hef_loaded(self):
- """Return True if this object has loaded the model HEF to the hardware device."""
- return self._hef_loaded
-
- def outputs_count(self):
- """Return the amount of output tensors that are returned from the hardware device for every
- input image.
- """
- return len(self.get_output_vstream_infos())
-
- def _clear_shapes(self):
- self._hw_consts = None
-
- @property
- def model_name(self):
- """Get the name of the current model.
-
- Returns:
- str: Model name.
- """
- if len(self._loaded_network_groups) == 1:
- return self._loaded_network_groups[0].name
- raise HailoHWObjectException(
- "This function is only supported when there is exactly 1 loaded network group. one should use HEF.get_network_group_names() / ConfiguredNetwork.name / ActivatedNetwork.name")
-
- def get_output_shapes(self):
- """Get the model output shapes, as returned to the user (without any hardware padding).
-
- Returns:
- Tuple of output shapes, sorted by the output names.
- """
- if len(self._loaded_network_groups) != 1:
- raise HailoHWObjectException("Calling get_output_shapes is only allowed when there is a single loaded network group")
- return self._loaded_network_groups[0].get_output_shapes()
-
-
-class HailoChipObject(HailoHWObject):
- """Hailo hardware device representation"""
- IS_NUMERIC = True
- IS_HARDWARE = True
-
- def __init__(self):
- """Create the Hailo Chip hardware object."""
- super(HailoChipObject, self).__init__()
- self._id = "Generic Hailo Device"
- self._control_object = None
- self._loaded_network_groups = []
- self._creation_pid = os.getpid()
-
- @property
- def control(self):
- """:class:`HailoControl <hailo_platform.drivers.control_object.HailoControl>`: Returns
- the control object of this device, which implements the control API of the Hailo device.
-
- .. attention:: Use the low level control API with care.
- """
- return self._control_object
-
- def get_all_input_layers_dtype(self):
- """Get the model inputs dtype.
-
- Returns:
- dict of :obj:'numpy.dtype': where the key is model input_layer name, and the value is dtype as the device expect to get for this input.
- """
- return {stream.name: HailoRTTransformUtils.get_dtype(stream.data_bytes) for stream in self.get_input_stream_infos()}
-
- def get_input_vstream_infos(self, network_name=None):
- """Get input vstreams information of a specific network group.
-
- Args:
- network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
-
- Returns:
- If there is exactly one configured network group, returns a list of
- :obj:`hailo_platform.drivers.hailort._pyhailort.VStreamInfo`: with all the information objects of all input vstreams
- """
-
- if len(self._loaded_network_groups) != 1:
- raise HailoHWObjectException("Access to network vstream info is only allowed when there is a single loaded network group")
- return self._loaded_network_groups[0].get_input_vstream_infos(network_name=network_name)
-
- def get_output_vstream_infos(self, network_name=None):
- """Get output vstreams information of a specific network group.
-
- Args:
- network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
-
- Returns:
- If there is exactly one configured network group, returns a list of
- :obj:`hailo_platform.drivers.hailort._pyhailort.VStreamInfo`: with all the information objects of all output vstreams
- """
-
- if len(self._loaded_network_groups) != 1:
- raise HailoHWObjectException("Access to network vstream info is only allowed when there is a single loaded network group")
- return self._loaded_network_groups[0].get_output_vstream_infos(network_name=network_name)
-
- def get_all_vstream_infos(self, network_name=None):
- """Get input and output vstreams information.
-
- Args:
- network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
-
- Returns:
- If there is exactly one configured network group, returns a list of
- :obj:`hailo_platform.drivers.hailort._pyhailort.VStreamInfo`: with all the information objects of all input and output vstreams
- """
-
- if len(self._loaded_network_groups) != 1:
- raise HailoHWObjectException("Access to network vstream info is only allowed when there is a single loaded network group")
- return self._loaded_network_groups[0].get_all_vstream_infos(network_name=network_name)
-
- def get_input_stream_infos(self, network_name=None):
- """Get the input low-level streams information of a specific network group.
-
- Args:
- network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
-
- Returns:
- If there is exactly one configured network group, returns a list of
- :obj:`hailo_platform.drivers.hailort._pyhailort.VStreamInfo`: with information objects
- of all input low-level streams.
- """
- if len(self._loaded_network_groups) != 1:
- raise HailoHWObjectException("Access to network stream info is only allowed when there is a single loaded network group")
- return self._loaded_network_groups[0].get_input_stream_infos(network_name=network_name)
-
- def get_output_stream_infos(self, network_name=None):
- """Get the output low-level streams information of a specific network group.
-
- Args:
- network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
-
- Returns:
- If there is exactly one configured network group, returns a list of
- :obj:`hailo_platform.drivers.hailort._pyhailort.VStreamInfo`: with information objects
- of all output low-level streams.
- """
- if len(self._loaded_network_groups) != 1:
- raise HailoHWObjectException("Access to network stream info is only allowed when there is a single loaded network group")
- return self._loaded_network_groups[0].get_output_stream_infos(network_name=network_name)
-
- def get_all_stream_infos(self, network_name=None):
- """Get input and output streams information of a specific network group.
-
- Args:
- network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
-
- Returns:
- If there is exactly one configured network group, returns a list of
- :obj:`hailo_platform.drivers.hailort._pyhailort.StreamInfo`: with all the information objects of all input and output streams
- """
-
- if len(self._loaded_network_groups) != 1:
- raise HailoHWObjectException("Access to network stream info is only allowed when there is a single loaded network group")
- return self._loaded_network_groups[0].get_all_stream_infos(network_name=network_name)
-
- @property
- def loaded_network_groups(self):
- """Getter for the property _loaded_network_groups.
-
- Returns:
- list of :obj:`ConfiguredNetwork`: List of the the configured network groups loaded on the device.
- """
- return self._loaded_network_groups
-
- @property
- def _loaded_network_group(self):
- if len(self._loaded_network_groups) != 1:
- raise HailoHWObjectException("Access to network layer info is only allowed when there is a single loaded network group")
- return self._loaded_network_groups[0]
-
- def configure(self, hef, configure_params_by_name={}):
- """Configures target device from HEF object.
-
- Args:
- hef (:class:`~hailo_platform.drivers.hailort.pyhailort.HEF`): HEF to configure the device from
- configure_params_by_name (dict, optional): Maps between each net_group_name to configure_params. If not provided, default params will be applied
- """
- if self._creation_pid != os.getpid():
- raise HailoRTException("Device can only be configured from the process it was created in.")
- configured_apps = self._control_object.configure(hef, configure_params_by_name)
- self._hef_loaded = True
- configured_networks = [ConfiguredNetwork(configured_app, self, hef) for configured_app in configured_apps]
- self._loaded_network_groups.extend(configured_networks)
- return configured_networks
-
- def get_input_shape(self, name=None):
- """Get the input shape (not padded) of a network.
-
- Args:
- name (str, optional): The name of the desired input. If a name is not provided, return
- the first input_dataflow shape.
-
- Returns:
- Tuple of integers representing the input_shape.
- """
- if name is None:
- name = self.get_input_vstream_infos()[0].name
-
- for input_vstream in self.get_input_vstream_infos():
- if input_vstream.name == name:
- return input_vstream.shape
-
- raise HailoHWObjectException("There is no input named {}! the input names are: {}".format(name,
- [input_vstream.name for input_vstream in self.get_input_vstream_infos()]))
-
- def get_index_from_name(self, name):
- """Get the index in the output list from the name.
-
- Args:
- name (str): The name of the output.
-
- Returns:
- int: The index of the layer name in the output list.
- """
- try:
- return self.sorted_output_layer_names.index(ensure_str(name))
- except ValueError:
- if len(self.sorted_output_layer_names) == 1:
- # Case regard to SDK-9366 - see Jira for details.
- self._logger.warning('Incorrect meta item - layer defuse_name does not match layer name.')
- return 0
- else:
- raise HailoHWObjectException("Could not get index for outputs properly.")
-
-
-class EthernetDevice(HailoChipObject):
- """Represents any Hailo hardware device that supports UDP control and dataflow."""
-
- NAME = InferenceTargets.UDP_CONTROLLER
-
- def __init__(
- self,
- remote_ip,
- remote_control_port=22401):
- """Create the Hailo UDP hardware object.
-
- Args:
- remote_ip (str): Device IP address.
- remote_control_port (int, optional): UDP port to which the device listens for control.
- Defaults to 22401.
- """
-
- super(EthernetDevice, self).__init__()
-
- self._remote_ip = remote_ip
- gc.collect()
- self._remote_control_port = remote_control_port
- # EthernetDevice __del__ function tries to release self._eth_device.
- # to avoid AttributeError if the __init__ func fails, we set it to None first.
- # https://stackoverflow.com/questions/6409644/is-del-called-on-an-object-that-doesnt-complete-init
- self._eth_device = None
- self._id = "{}".format(self._remote_ip)
-
- if not self.hef_loaded():
- self._open_device()
-
- identity = self._control_object._device_id
- self._hw_arch = BoardInformation.get_hw_arch_str(identity.device_architecture)
-
- @staticmethod
- def scan_devices(interface_name, timeout_seconds=3):
- """Scans for all eth devices on a specific network interface.
-
- Args:
- interface_name (str): Interface to scan.
- timeout_seconds (int, optional): timeout for scan operation. Defaults to 3.
- Returns:
- list of str: IPs of scanned devices.
- """
- udp_scanner = HailoUdpScan()
- return udp_scanner.scan_devices(interface_name, timeout_seconds=timeout_seconds)
-
- def _open_device(self):
- self._eth_device = InternalEthernetDevice(self._remote_ip, self._remote_control_port)
- self._control_object = UdpHcpControl(self._remote_ip, device=self._eth_device, remote_control_port=self._remote_control_port)
-
- def _close(self):
- if self._eth_device is not None:
- self._eth_device.release()
- self._eth_device = None
-
- def __enter__(self):
- if not self.hef_loaded:
- return None
- self._open_device()
- return self
-
- def __exit__(self, *args):
- self._close()
- return False
-
- def __del__(self):
- self._close()
-
- @property
- def remote_ip(self):
- """Return the IP of the remote device."""
- return self._remote_ip
-
-
-class PcieDevice(HailoChipObject):
- """Hailo PCIe production device representation."""
-
- NAME = InferenceTargets.PCIE_CONTROLLER
-
- def __init__(
- self,
- device_info=None):
-
- """Create the Hailo PCIe hardware object.
-
- Args:
- device_info (:obj:`hailo_platform.drivers.hailort.pyhailort.PcieDeviceInfo`, optional): Device info to create, call
- :func:`PcieDevice.scan_devices` to get list of all available devices.
- """
- super(PcieDevice, self).__init__()
-
- gc.collect()
- # PcieDevice __del__ function tries to release self._pcie_device.
- # to avoid AttributeError if the __init__ func fails, we set it to None first.
- # https://stackoverflow.com/questions/6409644/is-del-called-on-an-object-that-doesnt-complete-init
- self._pcie_device = None
- self._device_info = device_info
-
- if not self.hef_loaded():
- self._open_device()
-
- # At this point self._device_info is already initialized
- self._id = "{}".format(self._device_info)
-
- identity = self._control_object._device_id
- self._hw_arch = BoardInformation.get_hw_arch_str(identity.device_architecture)
-
- @staticmethod
- def scan_devices():
- """Scans for all pcie devices on the system.
-
- Returns:
- list of :obj:`hailo_platform.drivers.hailort.pyhailort.PcieDeviceInfo`
- """
- return InternalPcieDevice.scan_devices()
-
- def _open_device(self):
- self._pcie_device = InternalPcieDevice(self._device_info)
- self._device_info = self._pcie_device._device_info
- self._control_object = PcieHcpControl(device=self._pcie_device, device_info=self._device_info)
-
- def _close(self):
- if self._pcie_device is not None:
- self._pcie_device.release()
- self._pcie_device = None
-
- def __enter__(self):
- if not self.hef_loaded:
- return None
- self._open_device()
- return self
-
- def __exit__(self, *args):
- self._close()
- return False
-
- def __del__(self):
- self._close()
+from hailo_platform.pyhailort.hw_object import * # noqa F401
+++ /dev/null
-#!/usr/bin/env python
-import hailo_platform
-from hailo_platform.common.paths_manager.paths import SDKPaths, Singleton
-import os
-from future.utils import with_metaclass
-
-
-class PlatformPaths(with_metaclass(Singleton, SDKPaths)):
- def join_platform(self, path):
- return os.path.join(os.path.abspath(hailo_platform.__path__[0]), path)
--- /dev/null
+#!/usr/bin/env python
+
+"""Control operations for the Hailo hardware device."""
+import struct
+import sys
+import signal
+
+from builtins import object
+from abc import ABCMeta, abstractmethod
+from future.utils import with_metaclass
+
+from hailo_platform.common.logger.logger import default_logger
+
+from hailo_platform.pyhailort.hailo_control_protocol import BoardInformation, CoreInformation, DeviceArchitectureTypes, ExtendedDeviceInformation, HealthInformation
+from hailo_platform.pyhailort.power_measurement import SamplingPeriod, AveragingFactor, DvmTypes, PowerMeasurementTypes, MeasurementBufferIndex, _get_buffer_index_enum_member
+from hailo_platform.pyhailort.pyhailort import InternalPcieDevice, ExceptionWrapper
+
+import hailo_platform.pyhailort._pyhailort as _pyhailort
+
+
+class ControlObjectException(Exception):
+ """Raised on illegal ContolObject operation."""
+ pass
+
+
+class FirmwareUpdateException(Exception):
+ pass
+
+
+class HailoControl(with_metaclass(ABCMeta, object)):
+ """Control object that sends control operations to a Hailo hardware device."""
+
+ def __init__(self):
+ """Initializes a new HailoControl object."""
+ self._logger = default_logger()
+ self._device = None
+
+ if sys.platform != "win32":
+ signal.pthread_sigmask(signal.SIG_BLOCK, [signal.SIGWINCH])
+
+ @abstractmethod
+ def open(self):
+ """Initializes the resources needed for using a control device."""
+ pass
+
+ @abstractmethod
+ def close(self):
+ """Releases the resources that were allocated for the control device."""
+ pass
+
+ def configure(self, hef, configure_params_by_name={}):
+ """
+ Configures device from HEF object.
+
+ Args:
+ hef (:class:`~hailo_platform.pyhailort.pyhailort.HEF`): HEF to configure the
+ device from.
+ configure_params_by_name (dict, optional): Maps between each net_group_name to
+ configure_params. In case of a mismatch with net_groups_names, default params will
+ be used.
+ """
+ with ExceptionWrapper():
+ return self._device.configure(hef._hef, configure_params_by_name)
+
+ @abstractmethod
+ def chip_reset(self):
+ """Resets the device (chip reset)."""
+ pass
+
+ @abstractmethod
+ def read_memory(self, address, data_length):
+ """Reads memory from the Hailo chip.
+ Byte order isn't changed. The core uses little-endian byte order.
+
+ Args:
+ address (int): Physical address to read from.
+ data_length (int): Size to read in bytes.
+
+ Returns:
+ list of str: Memory read from the chip, each index in the list is a byte.
+ """
+ pass
+
+ @abstractmethod
+ def write_memory(self, address, data_buffer):
+ """Write memory to Hailo chip.
+ Byte order isn't changed. The core uses little-endian byte order.
+
+ Args:
+ address (int): Physical address to write to.
+ data_buffer (list of str): Data to write.
+ """
+ pass
+
+
+class HcpControl(HailoControl):
+ """Control object that uses the HCP protocol for controlling the device."""
+
+ WORD_SIZE = 4
+
+
+ def __init__(self):
+ super(HcpControl, self).__init__()
+
+ @property
+ def device_id(self):
+ """Getter for the device_id.
+
+ Returns:
+ str: A string ID of the device. BDF for PCIe devices, IP address for Ethernet devices, "Core" for core devices.
+ """
+ return self._device_id
+
+ def open(self):
+ """Initializes the resources needed for using a control device."""
+ pass
+
+ def close(self):
+ """Releases the resources that were allocated for the control device."""
+ pass
+
+ def chip_reset(self):
+ """Resets the device (chip reset)."""
+ with ExceptionWrapper():
+ return self._device.reset(_pyhailort.ResetDeviceMode.CHIP)
+
+ def nn_core_reset(self):
+ """Resets the nn_core."""
+ with ExceptionWrapper():
+ return self._device.reset(_pyhailort.ResetDeviceMode.NN_CORE)
+
+ def soft_reset(self):
+ """reloads the device firmware (soft reset)"""
+ with ExceptionWrapper():
+ return self._device.reset(_pyhailort.ResetDeviceMode.SOFT)
+
+ def forced_soft_reset(self):
+ """reloads the device firmware (forced soft reset)"""
+ with ExceptionWrapper():
+ return self._device.reset(_pyhailort.ResetDeviceMode.FORCED_SOFT)
+
+ def read_memory(self, address, data_length):
+ """Reads memory from the Hailo chip. Byte order isn't changed. The core uses little-endian
+ byte order.
+
+ Args:
+ address (int): Physical address to read from.
+ data_length (int): Size to read in bytes.
+
+ Returns:
+ list of str: Memory read from the chip, each index in the list is a byte
+ """
+ with ExceptionWrapper():
+ return self._device.read_memory(address, data_length)
+
+ def write_memory(self, address, data_buffer):
+ """Write memory to Hailo chip. Byte order isn't changed. The core uses little-endian byte
+ order.
+
+ Args:
+ address (int): Physical address to write to.
+ data_buffer (list of str): Data to write.
+ """
+ with ExceptionWrapper():
+ return self._device.write_memory(address, data_buffer, len(data_buffer))
+
+ def power_measurement(self, dvm=DvmTypes.AUTO, measurement_type=PowerMeasurementTypes.AUTO):
+ """Perform a single power measurement on an Hailo chip. It works with the default settings
+ where the sensor returns a new value every 2.2 ms without averaging the values.
+
+ Args:
+ dvm (:class:`~hailo_platform.pyhailort.pyhailort.DvmTypes`):
+ Which DVM will be measured. Default (:class:`~hailo_platform.pyhailort.pyhailort.DvmTypes.AUTO`) will be different according to the board: \n
+ Default (:class:`~hailo_platform.pyhailort.pyhailort.DvmTypes.AUTO`) for EVB is an approximation to the total power consumption of the chip in PCIe setups.
+ It sums :class:`~hailo_platform.pyhailort.pyhailort.DvmTypes.VDD_CORE`,
+ :class:`~hailo_platform.pyhailort.pyhailort.DvmTypes.MIPI_AVDD` and :class:`~hailo_platform.pyhailort.pyhailort.DvmTypes.AVDD_H`.
+ Only :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes.POWER` can measured with this option. \n
+ Default (:class:`~hailo_platform.pyhailort.pyhailort.DvmTypes.AUTO`) for platforms supporting current monitoring (such as M.2 and mPCIe): :class:`~hailo_platform.pyhailort.pyhailort.DvmTypes.OVERCURRENT_PROTECTION`
+ measurement_type
+ (:class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes`):
+ The type of the measurement.
+
+ Returns:
+ float: The measured power. \n
+ For :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes`: \n
+ - :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes.SHUNT_VOLTAGE`: Unit is mV. \n
+ - :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes.BUS_VOLTAGE`: Unit is mV. \n
+ - :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes.POWER`: Unit is W. \n
+ - :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes.CURRENT`: Unit is mA. \n
+
+
+ Note:
+ This function can perform measurements for more than just power. For all supported
+ measurement types, please look at
+ :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes`.
+ """
+ if self.device_id.device_architecture != DeviceArchitectureTypes.HAILO8_B0:
+ raise ControlObjectException("Invalid device architecture: {}".format(self.device_id.device_architecture))
+ with ExceptionWrapper():
+ return self._device.power_measurement(dvm, measurement_type)
+
+ def start_power_measurement(self, delay=None, averaging_factor=AveragingFactor.AVERAGE_256, sampling_period=SamplingPeriod.PERIOD_1100us):
+ """Start performing a long power measurement.
+
+ Args:
+ delay: Unused parameter. Will be removed in future versions.
+ averaging_factor (:class:`~hailo_platform.pyhailort.pyhailort.AveragingFactor`):
+ Number of samples per time period, sensor configuration value.
+ sampling_period (:class:`~hailo_platform.pyhailort.pyhailort.SamplingPeriod`):
+ Related conversion time, sensor configuration value. The sensor samples the power
+ every ``sampling_period`` [ms] and averages every ``averaging_factor`` samples. The
+ sensor provides a new value every: 2 * sampling_period * averaging_factor [ms]. The
+ firmware wakes up every ``delay`` [ms] and checks the sensor. If there is a new`
+ value to read from the sensor, the firmware reads it. Note that the average
+ calculated by the firmware is "average of averages", because it averages values
+ that have already been averaged by the sensor.
+ """
+ # TODO: Remove deprecated arg
+ if delay is not None:
+ self._logger.warning("Passing 'delay' to 'start_power_measurement()' is deprecated and will be removed in future versions")
+ with ExceptionWrapper():
+ return self._device.start_power_measurement(averaging_factor, sampling_period)
+
+ def stop_power_measurement(self):
+ """Stop performing a long power measurement. Deletes all saved results from the firmware.
+ Calling the function eliminates the start function settings for the averaging the samples,
+ and returns to the default values, so the sensor will return a new value every 2.2 ms
+ without averaging values.
+ """
+ with ExceptionWrapper():
+ return self._device.stop_power_measurement()
+
+ def set_power_measurement(self, buffer_index=MeasurementBufferIndex.MEASUREMENT_BUFFER_INDEX_0, dvm=DvmTypes.AUTO, measurement_type=PowerMeasurementTypes.AUTO):
+ """Set parameters for long power measurement on an Hailo chip.
+
+ Args:
+ buffer_index (:class:`~hailo_platform.pyhailort.pyhailort.MeasurementBufferIndex`): Index of the buffer on the firmware the data would be saved at.
+ Default is :class:`~hailo_platform.pyhailort.pyhailort.MeasurementBufferIndex.MEASUREMENT_BUFFER_INDEX_0`
+ dvm (:class:`~hailo_platform.pyhailort.pyhailort.DvmTypes`):
+ Which DVM will be measured. Default (:class:`~hailo_platform.pyhailort.pyhailort.DvmTypes.AUTO`) will be different according to the board: \n
+ Default (:class:`~hailo_platform.pyhailort.pyhailort.DvmTypes.AUTO`) for EVB is an approximation to the total power consumption of the chip in PCIe setups.
+ It sums :class:`~hailo_platform.pyhailort.pyhailort.DvmTypes.VDD_CORE`,
+ :class:`~hailo_platform.pyhailort.pyhailort.DvmTypes.MIPI_AVDD` and :class:`~hailo_platform.pyhailort.pyhailort.DvmTypes.AVDD_H`.
+ Only :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes.POWER` can measured with this option. \n
+ Default (:class:`~hailo_platform.pyhailort.pyhailort.DvmTypes.AUTO`) for platforms supporting current monitoring (such as M.2 and mPCIe): :class:`~hailo_platform.pyhailort.pyhailort.DvmTypes.OVERCURRENT_PROTECTION`
+ measurement_type
+ (:class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes`):
+ The type of the measurement.
+
+ Note:
+ This function can perform measurements for more than just power. For all supported measurement types
+ view :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes`
+ """
+ # TODO: Remove deprecated arg
+ if isinstance(buffer_index, int):
+ self._logger.warning("Passing integer as 'buffer_index' to 'set_power_measurement()' is deprecated. One should pass "
+ ":class:`~hailo_platform.pyhailort.pyhailort.MeasurementBufferIndex` as 'buffer_index' instead.")
+ buffer_index = _get_buffer_index_enum_member(buffer_index)
+ with ExceptionWrapper():
+ return self._device.set_power_measurement(buffer_index, dvm, measurement_type)
+
+ def get_power_measurement(self, buffer_index=MeasurementBufferIndex.MEASUREMENT_BUFFER_INDEX_0, should_clear=True):
+ """Read measured power from a long power measurement
+
+ Args:
+ buffer_index (:class:`~hailo_platform.pyhailort.pyhailort.MeasurementBufferIndex`): Index of the buffer on the firmware the data would be saved at.
+ Default is :class:`~hailo_platform.pyhailort.pyhailort.MeasurementBufferIndex.MEASUREMENT_BUFFER_INDEX_0`
+ should_clear (bool): Flag indicating if the results saved at the firmware will be deleted after reading.
+
+ Returns:
+ :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementData`:
+ Object containing measurement data \n
+ For :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes`: \n
+ - :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes.SHUNT_VOLTAGE`: Unit is mV. \n
+ - :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes.BUS_VOLTAGE`: Unit is mV. \n
+ - :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes.POWER`: Unit is W. \n
+ - :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes.CURRENT`: Unit is mA. \n
+
+ Note:
+ This function can perform measurements for more than just power.
+ For all supported measurement types view
+ :class:`~hailo_platform.pyhailort.pyhailort.PowerMeasurementTypes`.
+ """
+ if self.device_id.device_architecture != DeviceArchitectureTypes.HAILO8_B0:
+ raise ControlObjectException("Invalid device architecture: {}".format(self.device_id.device_architecture))
+ # TODO: Remove deprecated arg
+ if isinstance(buffer_index, int):
+ self._logger.warning("Passing integer as 'buffer_index' to 'get_power_measurement()' is deprecated. One should pass "
+ ":class:`~hailo_platform.pyhailort.pyhailort.MeasurementBufferIndex` as 'buffer_index' instead.")
+ buffer_index = _get_buffer_index_enum_member(buffer_index)
+ with ExceptionWrapper():
+ return self._device.get_power_measurement(buffer_index, should_clear)
+
+ def _examine_user_config(self):
+ with ExceptionWrapper():
+ return self._device.examine_user_config()
+
+ def read_user_config(self):
+ """Read the user configuration section as binary data.
+
+ Returns:
+ str: User config as a binary buffer.
+ """
+ with ExceptionWrapper():
+ return self._device.read_user_config()
+
+ def write_user_config(self, configuration):
+ """Write the user configuration.
+
+ Args:
+ configuration (str): A binary representation of a Hailo device configuration.
+ """
+ with ExceptionWrapper():
+ return self._device.write_user_config(configuration)
+
+ def _erase_user_config(self):
+ with ExceptionWrapper():
+ return self._device.erase_user_config()
+
+ def read_board_config(self):
+ """Read the board configuration section as binary data.
+
+ Returns:
+ str: Board config as a binary buffer.
+ """
+ with ExceptionWrapper():
+ return self._device.read_board_config()
+
+ def write_board_config(self, configuration):
+ """Write the static confuration.
+
+ Args:
+ configuration (str): A binary representation of a Hailo device configuration.
+ """
+ with ExceptionWrapper():
+ return self._device.write_board_config(configuration)
+
+ def identify(self):
+ """Gets the Hailo chip identification.
+
+ Returns:
+ class HailoIdentifyResponse with Protocol version.
+ """
+ with ExceptionWrapper():
+ response = self._device.identify()
+ board_information = BoardInformation(response.protocol_version, response.fw_version.major,
+ response.fw_version.minor, response.fw_version.revision, response.logger_version,
+ response.board_name, response.is_release, int(response.device_architecture), response.serial_number,
+ response.part_number, response.product_name)
+ return board_information
+
+ def core_identify(self):
+ """Gets the Core Hailo chip identification.
+
+ Returns:
+ class HailoIdentifyResponse with Protocol version.
+ """
+ with ExceptionWrapper():
+ response = self._device.core_identify()
+ core_information = CoreInformation(response.fw_version.major, response.fw_version.minor,
+ response.fw_version.revision, response.is_release)
+ return core_information
+
+ def set_fw_logger(self, level, interface_mask):
+ """Configure logger level and interface of sending.
+
+ Args:
+ level (FwLoggerLevel): The minimum logger level.
+ interface_mask (int): Output interfaces (mix of FwLoggerInterface).
+ """
+ with ExceptionWrapper():
+ return self._device.set_fw_logger(level, interface_mask)
+
+ def set_throttling_state(self, should_activate):
+ """Change throttling state of temperature protection component.
+
+ Args:
+ should_activate (bool): Should be true to enable or false to disable.
+ """
+ with ExceptionWrapper():
+ return self._device.set_throttling_state(should_activate)
+
+ def get_throttling_state(self):
+ """Get the current throttling state of temperature protection component.
+
+ Returns:
+ bool: true if temperature throttling is enabled, false otherwise.
+ """
+ with ExceptionWrapper():
+ return self._device.get_throttling_state()
+
+ def _set_overcurrent_state(self, should_activate):
+ """Control whether the overcurrent protection is enabled or disabled.
+
+ Args:
+ should_activate (bool): Should be true to enable or false to disable.
+ """
+ with ExceptionWrapper():
+ return self._device._set_overcurrent_state(should_activate)
+
+ def _get_overcurrent_state(self):
+ """Get the overcurrent protection state.
+
+ Returns:
+ bool: true if overcurrent protection is enabled, false otherwise.
+ """
+ with ExceptionWrapper():
+ return self._device._get_overcurrent_state()
+
+ @staticmethod
+ def _create_c_i2c_slave(pythonic_slave):
+ c_slave = _pyhailort.I2CSlaveConfig()
+ c_slave.endianness = pythonic_slave.endianness
+ c_slave.slave_address = pythonic_slave.slave_address
+ c_slave.register_address_size = pythonic_slave.register_address_size
+ c_slave.bus_index = pythonic_slave.bus_index
+ return c_slave
+
+ def i2c_write(self, slave, register_address, data):
+ """Write data to an I2C slave.
+
+ Args:
+ slave (:class:`hailo_platform.pyhailort.i2c_slaves.I2CSlave`): I2C slave
+ configuration.
+ register_address (int): The address of the register to which the data will be written.
+ data (str): The data that will be written.
+ """
+ c_slave = HcpControl._create_c_i2c_slave(slave)
+ with ExceptionWrapper():
+ return self._device.i2c_write(c_slave, register_address, data, len(data))
+
+ def i2c_read(self, slave, register_address, data_length):
+ """Read data from an I2C slave.
+
+ Args:
+ slave (:class:`hailo_platform.pyhailort.i2c_slaves.I2CSlave`): I2C slave
+ configuration.
+ register_address (int): The address of the register from which the data will be read.
+ data_length (int): The number of bytes to read.
+
+ Returns:
+ str: Data read from the I2C slave.
+ """
+ c_slave = HcpControl._create_c_i2c_slave(slave)
+ with ExceptionWrapper():
+ return self._device.i2c_read(c_slave, register_address, data_length)
+
+ def read_register(self, address):
+ """Read the value of a register from a given address.
+
+ Args:
+ address (int): Address to read register from.
+
+ Returns:
+ int: Value of the register
+ """
+ register_value, = struct.unpack('!I', self.read_memory(address, type(self).WORD_SIZE))
+ return register_value
+
+ def set_bit(self, address, bit_index):
+ """Set (turn on) a specific bit at a register from a given address.
+
+ Args:
+ address (int) : Address of the register to modify.
+ bit_index (int) : Index of the bit that would be set.
+ """
+ register_value = self.read_register(address)
+ register_value |= 1 << bit_index
+ self.write_memory(address, struct.pack('!I', register_value))
+
+ def reset_bit(self, address, bit_index):
+ """Reset (turn off) a specific bit at a register from a given address.
+
+ Args:
+ address (int) : Address of the register to modify.
+ bit_index (int) : Index of the bit that would be reset.
+ """
+ register_value = self.read_register(address)
+ register_value &= ~(1 << bit_index)
+ self.write_memory(address, struct.pack('!I', register_value))
+
+ def firmware_update(self, firmware_binary, should_reset=True):
+ """Update firmware binary on the flash.
+
+ Args:
+ firmware_binary (bytes): firmware binary stream.
+ should_reset (bool): Should a reset be performed after the update (to load the new firmware)
+ """
+ with ExceptionWrapper():
+ return self._device.firmware_update(firmware_binary, len(firmware_binary), should_reset)
+
+ def second_stage_update(self, second_stage_binary):
+ """Update second stage binary on the flash
+
+ Args:
+ second_stage_binary (bytes): second stage binary stream.
+ """
+ with ExceptionWrapper():
+ return self._device.second_stage_update(second_stage_binary, len(second_stage_binary))
+
+ def store_sensor_config(self, section_index, reset_data_size, sensor_type, config_file_path,
+ config_height=0, config_width=0, config_fps=0, config_name=None):
+
+ """Store sensor configuration to Hailo chip flash memory.
+
+ Args:
+ section_index (int): Flash section index to write to. [0-6]
+ reset_data_size (int): Size of reset configuration.
+ sensor_type (:class:`~hailo_platform.pyhailort.pyhailort.SensorConfigTypes`): Sensor type.
+ config_file_path (str): Sensor configuration file path.
+ config_height (int): Configuration resolution height.
+ config_width (int): Configuration resolution width.
+ config_fps (int): Configuration FPS.
+ config_name (str): Sensor configuration name.
+ """
+ if config_name is None:
+ config_name = "UNINITIALIZED"
+
+ with ExceptionWrapper():
+ return self._device.sensor_store_config(section_index, reset_data_size, sensor_type, config_file_path,
+ config_height, config_width, config_fps, config_name)
+
+ def store_isp_config(self, reset_config_size, isp_static_config_file_path, isp_runtime_config_file_path,
+ config_height=0, config_width=0, config_fps=0, config_name=None):
+ """Store sensor isp configuration to Hailo chip flash memory.
+
+ Args:
+ reset_config_size (int): Size of reset configuration.
+ isp_static_config_file_path (str): Sensor isp static configuration file path.
+ isp_runtime_config_file_path (str): Sensor isp runtime configuration file path.
+ config_height (int): Configuration resolution height.
+ config_width (int): Configuration resolution width.
+ config_fps (int): Configuration FPS.
+ config_name (str): Sensor configuration name.
+ """
+ if config_name is None:
+ config_name = "UNINITIALIZED"
+
+ with ExceptionWrapper():
+ return self._device.store_isp_config(reset_config_size, config_height, config_width,
+ config_fps, isp_static_config_file_path, isp_runtime_config_file_path, config_name)
+
+ def get_sensor_sections_info(self):
+ """Get sensor sections info from Hailo chip flash memory.
+
+ Returns:
+ Sensor sections info read from the chip flash memory.
+ """
+ with ExceptionWrapper():
+ return self._device.sensor_get_sections_info()
+
+ def sensor_set_generic_i2c_slave(self, slave_address, register_address_size, bus_index, should_hold_bus, endianness):
+ """Set a generic I2C slave for sensor usage.
+
+ Args:
+ sequence (int): Request/response sequence.
+ slave_address (int): The address of the I2C slave.
+ register_address_size (int): The size of the offset (in bytes).
+ bus_index (int): The number of the bus the I2C slave is behind.
+ should_hold_bus (bool): Hold the bus during the read.
+ endianness (:class:`~hailo_platform.pyhailort.pyhailort.Endianness`):
+ Big or little endian.
+ """
+ with ExceptionWrapper():
+ return self._device.sensor_set_generic_i2c_slave(slave_address, register_address_size, bus_index, should_hold_bus, endianness)
+
+ def set_sensor_i2c_bus_index(self, sensor_type, i2c_bus_index):
+ """Set the I2C bus to which the sensor of the specified type is connected.
+
+ Args:
+ sensor_type (:class:`~hailo_platform.pyhailort.pyhailort.SensorConfigTypes`): The sensor type.
+ i2c_bus_index (int): The I2C bus index of the sensor.
+ """
+ with ExceptionWrapper():
+ return self._device.sensor_set_i2c_bus_index(sensor_type, i2c_bus_index)
+
+ def load_and_start_sensor(self, section_index):
+ """Load the configuration with I2C in the section index.
+
+ Args:
+ section_index (int): Flash section index to load config from. [0-6]
+ """
+ with ExceptionWrapper():
+ return self._device.sensor_load_and_start_config(section_index)
+
+ def reset_sensor(self, section_index):
+ """Reset the sensor that is related to the section index config.
+
+ Args:
+ section_index (int): Flash section index to reset. [0-6]
+ """
+ with ExceptionWrapper():
+ return self._device.sensor_reset(section_index)
+
+ def wd_enable(self, cpu_id):
+ """Enable firmware watchdog.
+
+ Args:
+ cpu_id (:class:`~hailo_platform.pyhailort.pyhailort.HailoCpuId`): 0 for App CPU, 1 for Core CPU.
+ """
+ with ExceptionWrapper():
+ return self._device.wd_enable(cpu_id)
+
+ def wd_disable(self, cpu_id):
+ """Disable firmware watchdog.
+
+ Args:
+ cpu_id (:class:`~hailo_platform.pyhailort.pyhailort.HailoCpuId`): 0 for App CPU, 1 for Core CPU.
+ """
+ with ExceptionWrapper():
+ return self._device.wd_disable(cpu_id)
+
+ def wd_config(self, cpu_id, wd_cycles, wd_mode):
+ """Configure a firmware watchdog.
+
+ Args:
+ cpu_id (:class:`~hailo_platform.pyhailort.pyhailort.HailoCpuId`): 0 for App CPU, 1 for Core CPU.
+ wd_cycles (int): number of cycles until watchdog is triggered.
+ wd_mode (int): 0 - HW/SW mode, 1 - HW only mode
+ """
+ with ExceptionWrapper():
+ return self._device.wd_config(cpu_id, wd_cycles, wd_mode)
+
+ def previous_system_state(self, cpu_id):
+ """Read the FW previous system state.
+
+ Args:
+ cpu_id (:class:`~hailo_platform.pyhailort.pyhailort.HailoCpuId`): 0 for App CPU, 1 for Core CPU.
+ """
+ with ExceptionWrapper():
+ return self._device.previous_system_state(cpu_id)
+
+ def get_chip_temperature(self):
+ """Returns the latest temperature measurements from the 2 internal temperature sensors of the Hailo chip.
+
+ Returns:
+ :class:`~hailo_platform.pyhailort.pyhailort.TemperatureInfo`:
+ Temperature in celsius of the 2 internal temperature sensors (TS), and a sample
+ count (a running 16-bit counter)
+ """
+ with ExceptionWrapper():
+ return self._device.get_chip_temperature()
+
+ def get_extended_device_information(self):
+ with ExceptionWrapper():
+ response = self._device.get_extended_device_information()
+ device_information = ExtendedDeviceInformation(response.neural_network_core_clock_rate,
+ response.supported_features, response.boot_source, response.lcs, response.soc_id, response.eth_mac_address , response.unit_level_tracking_id, response.soc_pm_values)
+ return device_information
+
+ def _get_health_information(self):
+ with ExceptionWrapper():
+ response = self._device._get_health_information()
+ health_information = HealthInformation(response.overcurrent_protection_active, response.current_overcurrent_zone, response.red_overcurrent_threshold,
+ response.orange_overcurrent_threshold, response.temperature_throttling_active, response.current_temperature_zone, response.current_temperature_throttling_level,
+ response.temperature_throttling_levels, response.orange_temperature_threshold, response.orange_hysteresis_temperature_threshold,
+ response.red_temperature_threshold, response.red_hysteresis_temperature_threshold)
+ return health_information
+
+ def set_pause_frames(self, rx_pause_frames_enable):
+ """Enable/Disable Pause frames.
+
+ Args:
+ rx_pause_frames_enable (bool): False for disable, True for enable.
+ """
+ with ExceptionWrapper():
+ return self._device.set_pause_frames(rx_pause_frames_enable)
+
+ def test_chip_memories(self):
+ """test all chip memories using smart BIST
+
+ """
+ with ExceptionWrapper():
+ return self._device.test_chip_memories()
+
+ def _get_device_handle(self):
+ return self._device
+
+class UdpHcpControl(HcpControl):
+ """Control object that uses a HCP over UDP controller interface."""
+
+ def __init__(self, remote_ip, device=None, remote_control_port=22401, retries=2, response_timeout_seconds=10.0, ignore_socket_errors=False):
+ """Initializes a new UdpControllerControl object.
+
+ Args:
+ remote_ip (str): The IPv4 address of the remote Hailo device (X.X.X.X).
+ remote_control_port (int, optional): The port that the remote Hailo device listens on.
+ response_timeout_seconds (float, optional): Number of seconds to wait until a response is received.
+ ignore_socket_errors (bool, optional): Ignore socket error (might be usefull for debugging).
+ """
+ super(UdpHcpControl, self).__init__()
+
+ # In the C API we define the total amount of attempts, instead of the amount of retries.
+ max_number_of_attempts = retries + 1
+ response_timeout_milliseconds = int(response_timeout_seconds * 1000)
+ if device is None:
+ with ExceptionWrapper():
+ self.device = _pyhailort.Device.create_eth(remote_ip, remote_control_port,
+ response_timeout_milliseconds, max_number_of_attempts)
+ else:
+ self._device = device.device
+ self._device_id = self.identify()
+
+
+class PcieHcpControl(HcpControl):
+ """Control object that uses a HCP over PCIe controller interface."""
+
+ def __init__(self, device=None, device_info=None):
+ """Initializes a new HailoPcieController object."""
+ super(PcieHcpControl, self).__init__()
+
+ if device_info is None:
+ device_info = InternalPcieDevice.scan_devices()[0]
+
+ if device is None:
+ with ExceptionWrapper():
+ self._device = _pyhailort.Device.create_pcie(device_info)
+ else:
+ self._device = device.device
+ self._device_id = self.identify()
+
+ def set_notification_callback(self, callback_func, notification_id, opaque):
+ """Set a callback function to be called when a notification is received.
+
+ Args:
+ callback_func (function): Callback function with the parameters (device, notification, opaque).
+ Note that throwing exceptions is not supported and will cause the program to terminate with an error!
+ notification_id (NotificationId): Notification ID to register the callback to.
+ opauqe (object): User defined data.
+
+ Note:
+ The notifications thread is started and closed in the use_device() context, so
+ notifications can only be received there.
+ """
+ with ExceptionWrapper():
+ return self._device.set_notification_callback(callback_func, notification_id, opaque)
+
+ def remove_notification_callback(self, notification_id):
+ """Remove a notification callback which was already set.
+
+ Args:
+ notification_id (NotificationId): Notification ID to remove the callback from.
+ """
+ with ExceptionWrapper():
+ return self._device.remove_notification_callback(notification_id)
--- /dev/null
+#!/usr/bin/env python
+from builtins import str
+import netifaces as ni
+
+from netaddr import IPAddress, IPNetwork
+
+
+# As defined in sockios.h
+SIOCGIFTXQLEN = 0x8942
+# Interface name is 16 bytes (including NULL)
+SIOCGIFTXQLEN_FMT = "16sI"
+
+class NoInterfaceError(Exception):
+ """Raised by get_interface_from_ip when no matching interface was found"""
+ pass
+
+def get_interface_from_ip(ip_address):
+ """Returns the interface name associated with the given ip addressself.
+
+ Args:
+ ip_address (str): the IP address to query.
+
+ Returns:
+ str: The name of the interface matching the given IP address.
+ """
+
+ skipped_ifaces = []
+ for interface in ni.interfaces():
+ if ni.AF_INET not in ni.ifaddresses(interface):
+ skipped_ifaces.append(interface)
+ continue
+ af_inet_values = ni.ifaddresses(interface)[ni.AF_INET][0]
+ ip_addr, netmask = af_inet_values['addr'], af_inet_values['netmask']
+ if is_ip_in_network(ip_addr, netmask, ip_address):
+ return str(interface)
+
+ raise NoInterfaceError('No interface for {} found among {}'.format(ip_address, skipped_ifaces))
+
+
+def get_interface_address(interface_name):
+ """Returns the interface address associated with the given interface name.
+
+ Args:
+ interface_name (str): the name of the interface to query.
+
+ Returns:
+ str: The IP address of the interface matching the given interface_name.
+ """
+ af_inet_values = ni.ifaddresses(interface_name)[ni.AF_INET][0]
+ return af_inet_values['addr']
+
+
+def is_ip_in_network(network_ip, netmask, ip_in_question):
+ """Checks whether an IP address is located in a given network.
+
+ Args:
+ network_ip (str): the IP address of the network interface.
+ netmask (str): the netmask of the given networkself.
+ ip_in_question (str): the IP address to compare against the network.
+
+ Returns:
+ bool: whether the IP address belongs to the given network.
+ """
+
+ netmask_bits = IPAddress(netmask).netmask_bits()
+ return IPAddress(ip_in_question) in IPNetwork('{}/{}'.format(network_ip, netmask_bits))
--- /dev/null
+#!/usr/bin/env python
+"""
+.. module:: hailo_control_protocol
+ :synopsis: Implements a Hailo Control Protocol message.
+"""
+
+from builtins import object
+from enum import Enum, IntEnum
+
+import struct
+
+# Supported protocol and Firmware version of current SDK.
+SUPPORTED_PROTOCOL_VERSION = 2
+SUPPORTED_FW_MAJOR = 4
+SUPPORTED_FW_MINOR = 8
+SUPPORTED_FW_REVISION = 0
+
+MEGA_MULTIPLIER = 1000.0 * 1000.0
+
+
+class HailoControlProtocolException(Exception):
+ pass
+
+
+class DeviceArchitectureTypes(IntEnum):
+ HAILO8_A0 = 0
+ HAILO8_B0 = 1
+ MERCURY_CA = 2
+
+ def __str__(self):
+ return self.name
+
+class BoardInformation(object):
+ def __init__(self, protocol_version, fw_version_major, fw_version_minor, fw_version_revision,
+ logger_version, board_name, is_release, device_architecture, serial_number, part_number, product_name):
+ self.protocol_version = protocol_version
+ self.firmware_version = HailoFirmwareVersion.construct_from_params(fw_version_major, fw_version_minor, fw_version_revision, is_release, HailoFirmwareType.APP)
+ self.logger_version = logger_version
+ self.board_name = board_name
+ self.is_release = is_release
+ self.device_architecture = DeviceArchitectureTypes(device_architecture)
+ self.serial_number = serial_number
+ self.part_number = part_number
+ self.product_name = product_name
+
+ def _string_field_str(self, string_field):
+ # Return <Not Configured> if the string field is empty
+ return string_field.rstrip('\x00') or "<Not Configured>"
+
+ def __str__(self):
+ """Returns:
+ str: Human readable string.
+ """
+ return 'Control Protocol Version: {}\n' \
+ 'Firmware Version: {}\n' \
+ 'Logger Version: {}\n' \
+ 'Board Name: {}\n' \
+ 'Device Architecture: {}\n' \
+ 'Serial Number: {}\n' \
+ 'Part Number: {}\n' \
+ 'Product Name: {}\n'.format(
+ self.protocol_version,
+ self.firmware_version,
+ self.logger_version,
+ self.board_name.rstrip('\x00'),
+ str(self.device_architecture),
+ self._string_field_str(self.serial_number),
+ self._string_field_str(self.part_number),
+ self._string_field_str(self.product_name))
+
+ def __repr__(self):
+ """Returns:
+ str: Human readable string.
+ """
+ return self.__str__()
+
+ @staticmethod
+ def get_hw_arch_str(device_arch):
+ if device_arch == DeviceArchitectureTypes.HAILO8_B0:
+ return 'hailo8'
+ elif device_arch == DeviceArchitectureTypes.MERCURY_CA:
+ return 'mercury'
+ else:
+ raise HailoControlProtocolException("Unsupported device architecture.")
+
+class CoreInformation(object):
+ def __init__(self, fw_version_major, fw_version_minor, fw_version_revision, is_release):
+ self.firmware_version = HailoFirmwareVersion.construct_from_params(fw_version_major, fw_version_minor, fw_version_revision, is_release, HailoFirmwareType.CORE)
+ self.is_release = is_release
+
+ def __str__(self):
+ """Returns:
+ str: Human readable string.
+ """
+ return 'Core Firmware Version: {}'.format(
+ self.firmware_version)
+
+ def __repr__(self):
+ """Returns:
+ str: Human readable string.
+ """
+ return self.__str__()
+
+class TemperatureThrottlingLevel(object):
+ def __init__(self, level_number, temperature_threshold, hysteresis_temperature_threshold, throttling_nn_clock_freq):
+ self.level_number = level_number
+ self.temperature_threshold = temperature_threshold
+ self.hysteresis_temperature_threshold = hysteresis_temperature_threshold
+ self.throttling_nn_clock_freq = throttling_nn_clock_freq
+
+ def __str__(self):
+ """Returns:
+ str: Human readable string.
+ """
+ return 'Temperature Throttling Level {}: \n' \
+ 'Temperature Threshold: {}\n' \
+ 'Hysteresis Temperature Threshold: {}\n' \
+ 'Throttling NN Clock Frequency: {}\n' \
+ .format(self.level_number, self.temperature_threshold, self.hysteresis_temperature_threshold, self.throttling_nn_clock_freq)
+
+ def __repr__(self):
+ return self.__str__()
+
+class HealthInformation(object):
+ def __init__(self, overcurrent_protection_active, current_overcurrent_zone, red_overcurrent_threshold, orange_overcurrent_threshold,
+ temperature_throttling_active, current_temperature_zone, current_temperature_throttling_level,
+ temperature_throttling_levels, orange_temperature_threshold, orange_hysteresis_temperature_threshold,
+ red_temperature_threshold, red_hysteresis_temperature_threshold):
+ self.overcurrent_protection_active = overcurrent_protection_active
+ self.current_overcurrent_zone = current_overcurrent_zone
+ self.red_overcurrent_threshold = red_overcurrent_threshold
+ self.orange_overcurrent_threshold = orange_overcurrent_threshold
+ self.temperature_throttling_active = temperature_throttling_active
+ self.current_temperature_zone = current_temperature_zone
+ self.current_temperature_throttling_level = current_temperature_throttling_level
+ self.orange_temperature_threshold = orange_temperature_threshold
+ self.orange_hysteresis_temperature_threshold = orange_hysteresis_temperature_threshold
+ self.red_temperature_threshold = red_temperature_threshold
+ self.red_hysteresis_temperature_threshold = red_hysteresis_temperature_threshold
+
+ # Add TemperatureThrottlingLevel in case it has new throttling_nn_clock_freq. level_number can be used as only last
+ # levels can be with the same freq
+ self.temperature_throttling_levels = []
+ if self.temperature_throttling_active:
+ throttling_nn_clock_frequencies = []
+ for level_number, temperature_throttling_level in enumerate(temperature_throttling_levels):
+ if temperature_throttling_level.throttling_nn_clock_freq not in throttling_nn_clock_frequencies:
+ throttling_nn_clock_frequencies.append(temperature_throttling_level.throttling_nn_clock_freq)
+ self.temperature_throttling_levels.append(TemperatureThrottlingLevel(level_number,
+ temperature_throttling_level.temperature_threshold,
+ temperature_throttling_level.hysteresis_temperature_threshold,
+ temperature_throttling_level.throttling_nn_clock_freq))
+ def __repr__(self):
+ return self.__str__()
+
+ def __str__(self):
+ """Returns:
+ str: Human readable string.
+ """
+ temperature_throttling_levels_str = "\n".join(["\n\n{}\n".format(str(temperature_throttling_level)) for temperature_throttling_level in self.temperature_throttling_levels]) \
+ if self.temperature_throttling_active else "<Temperature throttling is disabled>"
+ return 'Overcurrent Protection Active: {}\n' \
+ 'Overcurrent Protection Current Overcurrent Zone: {}\n' \
+ 'Overcurrent Protection Red Threshold: {}\n' \
+ 'Overcurrent Protection Orange Threshold: {}\n' \
+ 'Temperature Protection Red Threshold: {}\n' \
+ 'Temperature Protection Red Hysteresis Threshold: {}\n' \
+ 'Temperature Protection Orange Threshold: {}\n' \
+ 'Temperature Protection Orange Hysteresis Threshold: {}\n' \
+ 'Temperature Protection Throttling State: {}\n' \
+ 'Temperature Protection Current Zone: {}\n' \
+ 'Temperature Protection Current Throttling Level: {}\n' \
+ 'Temperature Protection Throttling Levels: {}' \
+ .format(self.overcurrent_protection_active, self.current_overcurrent_zone, self.red_overcurrent_threshold,
+ self.orange_overcurrent_threshold, self.red_temperature_threshold,
+ self.red_hysteresis_temperature_threshold, self.orange_temperature_threshold,
+ self.orange_hysteresis_temperature_threshold, self.temperature_throttling_active,
+ self.current_temperature_zone, self.current_temperature_throttling_level, temperature_throttling_levels_str)
+
+class ExtendedDeviceInformation(object):
+ def __init__(self, neural_network_core_clock_rate, supported_features, boot_source, lcs, soc_id, eth_mac_address, unit_level_tracking_id, soc_pm_values):
+ self.neural_network_core_clock_rate = neural_network_core_clock_rate
+ self.supported_features = SupportedFeatures(supported_features)
+ self.boot_source = boot_source
+ self.lcs = lcs
+ self.soc_id = soc_id
+ self.eth_mac_address = eth_mac_address
+ self.unit_level_tracking_id = unit_level_tracking_id
+ self.soc_pm_values = soc_pm_values
+
+ def __str__(self):
+ """Returns:
+ str: Human readable string.
+ """
+ string = 'Neural Network Core Clock Rate: {}MHz\n' \
+ '{}' \
+ 'Boot source: {}\n' \
+ 'LCS: {}\n'.format(
+ self.neural_network_core_clock_rate / MEGA_MULTIPLIER,
+ str(self.supported_features),
+ str(self.boot_source.name),
+ str(self.lcs))
+ if any(self.soc_id):
+ string += 'SoC ID: ' + (self.soc_id.hex())
+
+ if any(self.eth_mac_address):
+ string += '\nMAC Address: ' + (":".join("{:02X}".format(i) for i in self.eth_mac_address))
+
+ if any(self.unit_level_tracking_id):
+ string += '\nULT ID: ' + (self.unit_level_tracking_id.hex())
+
+ if any(self.soc_pm_values):
+ string += '\nPM Values: ' + (self.soc_pm_values.hex())
+
+
+ return string
+
+ def __repr__(self):
+ """Returns:
+ str: Human readable string.
+ """
+ return self.__str__()
+
+class HailoFirmwareMode(Enum):
+ """Indication that firmware version is stable and official """
+ DEVELOP = 'develop'
+ RELEASE = 'release'
+
+
+class HailoFirmwareType(Enum):
+ """Indication the firmware type """
+ CORE = 'core'
+ APP = 'app'
+
+
+class HailoFirmwareVersion(object):
+ """Represents a Hailo chip firmware version."""
+ DEV_BIT = 0x80000000
+ CORE_BIT = 0x08000000
+ FW_VERSION_FORMAT = '<III'
+
+ def __init__(self, firmware_version_buffer, is_release, fw_type):
+ """Initialize a new Hailo Firmware Version object.
+
+ Args:
+ firmware_version_buffer (str): A buffer containing the firmware version struct.
+ is_release (bool, optional): Flag indicating if firmware is at develop/release mode.
+ None indicates unknown
+ """
+ self.major, self.minor, self.revision = struct.unpack(
+ self.FW_VERSION_FORMAT,
+ firmware_version_buffer)
+
+ self.fw_type = fw_type
+ self.mode = HailoFirmwareMode.RELEASE if is_release else HailoFirmwareMode.DEVELOP
+
+ self.revision &= ~(self.CORE_BIT | self.DEV_BIT)
+
+ def __str__(self):
+ """Returns:
+ str: Firmware version in a human readable format.
+ """
+ return '{}.{}.{} ({},{})'.format(self.major, self.minor, self.revision, self.mode.value, self.fw_type.value)
+
+ @classmethod
+ def construct_from_params(cls, major, minor, revision, is_release, fw_type):
+ """Returns:
+ class HailoFirmwareVersion : with the given Firmware version.
+ """
+ return cls(struct.pack(HailoFirmwareVersion.FW_VERSION_FORMAT, major, minor, revision), is_release, fw_type)
+
+ @property
+ def comparable_value(self):
+ """A value that could be compared to other firmware versions."""
+ return (self.major << 64) + (self.minor << 32) + (self.revision)
+
+ def __hash__(self):
+ return self.comparable_value
+
+ def __eq__(self, other):
+ return self.comparable_value == other.comparable_value
+
+ # TODO: Required for Python2 BW compatibility (SDK-10038)
+ # This impl' comes by default in Python3
+ def __ne__(self, other):
+ return not (self == other)
+
+ def __lt__(self, other):
+ return self.comparable_value < other.comparable_value
+
+ def check_protocol_compatibility(self, other):
+ return ((self.major == other.major) and (self.minor == other.minor))
+
+class SupportedFeatures(object):
+ def __init__(self, supported_features):
+ self.ethernet = supported_features.ethernet
+ self.mipi = supported_features.mipi
+ self.pcie = supported_features.pcie
+ self.current_monitoring = supported_features.current_monitoring
+ self.mdio = supported_features.mdio
+
+ def _feature_str(self, feature_name, is_feature_enabled):
+ return '{}: {}\n'.format(feature_name, 'Enabled' if is_feature_enabled else 'Disabled')
+
+ def __str__(self):
+ """Returns:
+ str: Human readable string.
+ """
+ return 'Device supported features: \n' + \
+ self._feature_str('Ethernet', self.ethernet) + \
+ self._feature_str('MIPI', self.mipi) + \
+ self._feature_str('PCIE', self.pcie) + \
+ self._feature_str('Current Monitoring', self.current_monitoring) + \
+ self._feature_str('MDIO', self.mdio)
+
+ def __repr__(self):
+ """Returns:
+ str: Human readable string.
+ """
+ return self.__str__()
+
+ def _is_feature_enabled(self, feature):
+ return (self.supported_features & feature) != 0
--- /dev/null
+#!/usr/bin/env python
+
+"""Hailo hardware API"""
+from __future__ import division
+
+import gc
+import os
+
+from contextlib import contextmanager
+
+from hailo_platform.pyhailort.control_object import UdpHcpControl, PcieHcpControl
+from hailo_platform.common.logger.logger import default_logger
+from hailo_platform.pyhailort.hailo_control_protocol import BoardInformation
+
+from hailo_platform.pyhailort.pyhailort import ConfiguredNetwork, InternalEthernetDevice, InternalPcieDevice, HailoRTTransformUtils, HailoUdpScan, HailoRTException
+
+
+class InferenceTargets(object):
+ """Enum-like class with all inference targets supported by the HailoRT."""
+ UNINITIALIZED = 'uninitialized'
+ UDP_CONTROLLER = 'udp'
+ PCIE_CONTROLLER = 'pcie'
+
+class HailoHWObjectException(Exception):
+ """Raised in any error related to Hailo hardware."""
+ pass
+
+
+class HailoHWObject(object):
+ """Abstract Hailo hardware device representation."""
+
+ NAME = InferenceTargets.UNINITIALIZED
+ IS_HARDWARE = True
+
+ def __init__(self):
+ """Create the Hailo hardware object."""
+ self._last_interact_time = None
+ self._total_time = None
+ self._id = None
+ self._hw_arch = None
+ self._logger = default_logger()
+ self._debug = False
+ self._is_device_used = False
+ self._hef_loaded = False
+
+ # TODO: HRT-6310 Remove this.
+ def __eq__(self, other):
+ return type(self).NAME == other
+
+ @property
+ def name(self):
+ """str: The name of this target. Valid values are defined by :class:`~hailo_platform.pyhailort.hw_object.InferenceTargets`"""
+ return type(self).NAME
+
+ @property
+ def is_hardware(self):
+ """bool: Indicates this target runs on a physical hardware device."""
+ return type(self).IS_HARDWARE
+
+ @property
+ def device_id(self):
+ """Getter for the device_id.
+
+ Returns:
+ str: A string ID of the device. BDF for PCIe devices, IP address for Ethernet devices, "Core" for core devices.
+ """
+ return self._id
+
+ @property
+ def sorted_output_layer_names(self):
+ """Getter for the property sorted_output_names.
+ Returns:
+ list of str: Sorted list of the output layer names.
+ """
+ if len(self._loaded_network_groups) != 1:
+ raise HailoHWObjectException("Access to sorted_output_layer_names is only allowed when there is a single loaded network group")
+ return self._loaded_network_groups[0].get_sorted_output_names()
+
+ @contextmanager
+ def use_device(self, *args, **kwargs):
+ """A context manager that wraps the usage of the device (deprecated)."""
+ self._is_device_used = True
+ yield
+ self._is_device_used = False
+
+ def get_output_device_layer_to_original_layer_map(self):
+ """Get a mapping between the device outputs to the layers' names they represent.
+
+ Returns:
+ dict: Keys are device output names and values are lists of layers' names.
+ """
+ if len(self._loaded_network_groups) != 1:
+ raise HailoHWObjectException("Access to layer names is only allowed when there is a single loaded network group")
+ return {stream_info.name : self._loaded_network_groups[0].get_vstream_names_from_stream_name(stream_info.name)
+ for stream_info in self.get_output_stream_infos()}
+
+ def get_original_layer_to_device_layer_map(self):
+ """Get a mapping between the layer names and the device outputs that contain them.
+
+ Returns:
+ dict: Keys are the names of the layers and values are device outputs names.
+ """
+ if len(self._loaded_network_groups) != 1:
+ raise HailoHWObjectException("Access to layer names is only allowed when there is a single loaded network group")
+ return {vstream_info.name : self._loaded_network_groups[0].get_stream_names_from_vstream_name(vstream_info.name)
+ for vstream_info in self.get_output_vstream_infos()}
+
+ @property
+ def device_input_layers(self):
+ """Get a list of the names of the device's inputs."""
+ return [layer.name for layer in self.get_input_stream_infos()]
+
+ @property
+ def device_output_layers(self):
+ """Get a list of the names of the device's outputs."""
+ return [layer.name for layer in self.get_output_stream_infos()]
+
+ def hef_loaded(self):
+ """Return True if this object has loaded the model HEF to the hardware device."""
+ return self._hef_loaded
+
+ def outputs_count(self):
+ """Return the amount of output tensors that are returned from the hardware device for every
+ input image.
+ """
+ return len(self.get_output_vstream_infos())
+
+ def _clear_shapes(self):
+ self._hw_consts = None
+
+ @property
+ def model_name(self):
+ """Get the name of the current model.
+
+ Returns:
+ str: Model name.
+ """
+ if len(self._loaded_network_groups) == 1:
+ return self._loaded_network_groups[0].name
+ raise HailoHWObjectException(
+ "This function is only supported when there is exactly 1 loaded network group. one should use HEF.get_network_group_names() / ConfiguredNetwork.name / ActivatedNetwork.name")
+
+ def get_output_shapes(self):
+ """Get the model output shapes, as returned to the user (without any hardware padding).
+
+ Returns:
+ Tuple of output shapes, sorted by the output names.
+ """
+ if len(self._loaded_network_groups) != 1:
+ raise HailoHWObjectException("Calling get_output_shapes is only allowed when there is a single loaded network group")
+ return self._loaded_network_groups[0].get_output_shapes()
+
+
+class HailoChipObject(HailoHWObject):
+ """Hailo hardware device representation"""
+
+ def __init__(self):
+ """Create the Hailo Chip hardware object."""
+ super(HailoChipObject, self).__init__()
+ self._id = "Generic Hailo Device"
+ self._control_object = None
+ self._loaded_network_groups = []
+ self._creation_pid = os.getpid()
+
+ @property
+ def control(self):
+ """:class:`HailoControl <hailo_platform.pyhailort.control_object.HailoControl>`: Returns
+ the control object of this device, which implements the control API of the Hailo device.
+
+ .. attention:: Use the low level control API with care.
+ """
+ if self._control_object is None:
+ raise HailoRTException(
+ "The device has been released and is not usable."
+ " Device is released when the function `release()` is called explicitly, or when created using a context manager and goes out of scope.")
+ return self._control_object
+
+ def get_all_input_layers_dtype(self):
+ """Get the model inputs dtype.
+
+ Returns:
+ dict of :obj:'numpy.dtype': where the key is model input_layer name, and the value is dtype as the device expect to get for this input.
+ """
+ return {stream.name: HailoRTTransformUtils.get_dtype(stream.data_bytes) for stream in self.get_input_stream_infos()}
+
+ def get_input_vstream_infos(self, network_name=None):
+ """Get input vstreams information of a specific network group.
+
+ Args:
+ network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
+
+ Returns:
+ If there is exactly one configured network group, returns a list of
+ :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with all the information objects of all input vstreams
+ """
+
+ if len(self._loaded_network_groups) != 1:
+ raise HailoHWObjectException("Access to network vstream info is only allowed when there is a single loaded network group")
+ return self._loaded_network_groups[0].get_input_vstream_infos(network_name=network_name)
+
+ def get_output_vstream_infos(self, network_name=None):
+ """Get output vstreams information of a specific network group.
+
+ Args:
+ network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
+
+ Returns:
+ If there is exactly one configured network group, returns a list of
+ :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with all the information objects of all output vstreams
+ """
+
+ if len(self._loaded_network_groups) != 1:
+ raise HailoHWObjectException("Access to network vstream info is only allowed when there is a single loaded network group")
+ return self._loaded_network_groups[0].get_output_vstream_infos(network_name=network_name)
+
+ def get_all_vstream_infos(self, network_name=None):
+ """Get input and output vstreams information.
+
+ Args:
+ network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
+
+ Returns:
+ If there is exactly one configured network group, returns a list of
+ :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with all the information objects of all input and output vstreams
+ """
+
+ if len(self._loaded_network_groups) != 1:
+ raise HailoHWObjectException("Access to network vstream info is only allowed when there is a single loaded network group")
+ return self._loaded_network_groups[0].get_all_vstream_infos(network_name=network_name)
+
+ def get_input_stream_infos(self, network_name=None):
+ """Get the input low-level streams information of a specific network group.
+
+ Args:
+ network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
+
+ Returns:
+ If there is exactly one configured network group, returns a list of
+ :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with information objects
+ of all input low-level streams.
+ """
+ if len(self._loaded_network_groups) != 1:
+ raise HailoHWObjectException("Access to network stream info is only allowed when there is a single loaded network group")
+ return self._loaded_network_groups[0].get_input_stream_infos(network_name=network_name)
+
+ def get_output_stream_infos(self, network_name=None):
+ """Get the output low-level streams information of a specific network group.
+
+ Args:
+ network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
+
+ Returns:
+ If there is exactly one configured network group, returns a list of
+ :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with information objects
+ of all output low-level streams.
+ """
+ if len(self._loaded_network_groups) != 1:
+ raise HailoHWObjectException("Access to network stream info is only allowed when there is a single loaded network group")
+ return self._loaded_network_groups[0].get_output_stream_infos(network_name=network_name)
+
+ def get_all_stream_infos(self, network_name=None):
+ """Get input and output streams information of a specific network group.
+
+ Args:
+ network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
+
+ Returns:
+ If there is exactly one configured network group, returns a list of
+ :obj:`hailo_platform.pyhailort._pyhailort.StreamInfo`: with all the information objects of all input and output streams
+ """
+
+ if len(self._loaded_network_groups) != 1:
+ raise HailoHWObjectException("Access to network stream info is only allowed when there is a single loaded network group")
+ return self._loaded_network_groups[0].get_all_stream_infos(network_name=network_name)
+
+ @property
+ def loaded_network_groups(self):
+ """Getter for the property _loaded_network_groups.
+
+ Returns:
+ list of :obj:`ConfiguredNetwork`: List of the the configured network groups loaded on the device.
+ """
+ return self._loaded_network_groups
+
+ @property
+ def _loaded_network_group(self):
+ if len(self._loaded_network_groups) != 1:
+ raise HailoHWObjectException("Access to network layer info is only allowed when there is a single loaded network group")
+ return self._loaded_network_groups[0]
+
+ def configure(self, hef, configure_params_by_name={}):
+ """Configures target device from HEF object.
+
+ Args:
+ hef (:class:`~hailo_platform.pyhailort.pyhailort.HEF`): HEF to configure the device from
+ configure_params_by_name (dict, optional): Maps between each net_group_name to configure_params. If not provided, default params will be applied
+ """
+ if self._creation_pid != os.getpid():
+ raise HailoRTException("Device can only be configured from the process it was created in.")
+ configured_apps = self.control.configure(hef, configure_params_by_name)
+ self._hef_loaded = True
+ configured_networks = [ConfiguredNetwork(configured_app, self, hef) for configured_app in configured_apps]
+ self._loaded_network_groups.extend(configured_networks)
+ return configured_networks
+
+ def get_input_shape(self, name=None):
+ """Get the input shape (not padded) of a network.
+
+ Args:
+ name (str, optional): The name of the desired input. If a name is not provided, return
+ the first input_dataflow shape.
+
+ Returns:
+ Tuple of integers representing the input_shape.
+ """
+ if name is None:
+ name = self.get_input_vstream_infos()[0].name
+
+ for input_vstream in self.get_input_vstream_infos():
+ if input_vstream.name == name:
+ return input_vstream.shape
+
+ raise HailoHWObjectException("There is no input named {}! the input names are: {}".format(name,
+ [input_vstream.name for input_vstream in self.get_input_vstream_infos()]))
+
+ def get_index_from_name(self, name):
+ """Get the index in the output list from the name.
+
+ Args:
+ name (str): The name of the output.
+
+ Returns:
+ int: The index of the layer name in the output list.
+ """
+ try:
+ return self.sorted_output_layer_names.index(name)
+ except ValueError:
+ if len(self.sorted_output_layer_names) == 1:
+ # Case regard to SDK-9366 - see Jira for details.
+ self._logger.warning('Incorrect meta item - layer defuse_name does not match layer name.')
+ return 0
+ else:
+ raise HailoHWObjectException("Could not get index for outputs properly.")
+
+ def release(self):
+ """
+ Release the allocated resources of the device. This function should be called when working with the device not as context-manager.
+ Note: After calling this function, the device will not be usable.
+ """
+ if self._device is not None:
+ self._device.release()
+ self._device = None
+ self._control_object = None
+
+
+class EthernetDevice(HailoChipObject):
+ """Represents any Hailo hardware device that supports UDP control and dataflow."""
+
+ NAME = InferenceTargets.UDP_CONTROLLER
+
+ def __init__(
+ self,
+ remote_ip,
+ remote_control_port=22401):
+ """Create the Hailo UDP hardware object.
+
+ Args:
+ remote_ip (str): Device IP address.
+ remote_control_port (int, optional): UDP port to which the device listens for control.
+ Defaults to 22401.
+ """
+
+ super(EthernetDevice, self).__init__()
+
+ gc.collect()
+
+ self._remote_ip = remote_ip
+ self._remote_control_port = remote_control_port
+ # EthernetDevice __del__ function tries to release self._device.
+ # to avoid AttributeError if the __init__ func fails, we set it to None first.
+ # https://stackoverflow.com/questions/6409644/is-del-called-on-an-object-that-doesnt-complete-init
+ self._device = None
+ self._control_object = None
+
+ self._open_device()
+
+ self._id = "{}".format(self._remote_ip)
+ identity = self._control_object._device_id
+ self._hw_arch = BoardInformation.get_hw_arch_str(identity.device_architecture)
+
+ @staticmethod
+ def scan_devices(interface_name, timeout_seconds=3):
+ """Scans for all eth devices on a specific network interface.
+
+ Args:
+ interface_name (str): Interface to scan.
+ timeout_seconds (int, optional): timeout for scan operation. Defaults to 3.
+ Returns:
+ list of str: IPs of scanned devices.
+ """
+ udp_scanner = HailoUdpScan()
+ return udp_scanner.scan_devices(interface_name, timeout_seconds=timeout_seconds)
+
+ def _open_device(self):
+ self._device = InternalEthernetDevice(self._remote_ip, self._remote_control_port)
+ self._control_object = UdpHcpControl(self._remote_ip, device=self._device, remote_control_port=self._remote_control_port)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ self.release()
+ return False
+
+ def __del__(self):
+ self.release()
+
+ @property
+ def remote_ip(self):
+ """Return the IP of the remote device."""
+ return self._remote_ip
+
+
+class PcieDevice(HailoChipObject):
+ """Hailo PCIe production device representation."""
+
+ NAME = InferenceTargets.PCIE_CONTROLLER
+
+ def __init__(
+ self,
+ device_info=None):
+
+ """Create the Hailo PCIe hardware object.
+
+ Args:
+ device_info (:obj:`hailo_platform.pyhailort.pyhailort.PcieDeviceInfo`, optional): Device info to create, call
+ :func:`PcieDevice.scan_devices` to get list of all available devices.
+ """
+ super(PcieDevice, self).__init__()
+
+ gc.collect()
+ # PcieDevice __del__ function tries to release self._device.
+ # to avoid AttributeError if the __init__ func fails, we set it to None first.
+ # https://stackoverflow.com/questions/6409644/is-del-called-on-an-object-that-doesnt-complete-init
+ self._device = None
+ self._device_info = None
+ self._control_object = None
+
+ self._open_device(device_info)
+
+ # At this point self._device_info is already initialized
+ self._id = "{}".format(self._device_info)
+ identity = self._control_object._device_id
+ self._hw_arch = BoardInformation.get_hw_arch_str(identity.device_architecture)
+
+ @staticmethod
+ def scan_devices():
+ """Scans for all pcie devices on the system.
+
+ Returns:
+ list of :obj:`hailo_platform.pyhailort.pyhailort.PcieDeviceInfo`
+ """
+ return InternalPcieDevice.scan_devices()
+
+ def _open_device(self, device_info):
+ self._device = InternalPcieDevice(device_info)
+ self._device_info = self._device._device_info # Handeling a case where device_info is None
+ self._control_object = PcieHcpControl(device=self._device, device_info=self._device_info)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ self.release()
+ return False
+
+ def __del__(self):
+ self.release()
--- /dev/null
+#!/usr/bin/env python
+from builtins import object
+import struct
+
+from hailo_platform.common.logger.logger import default_logger
+from hailo_platform.pyhailort.pyhailort import Endianness
+logger = default_logger()
+
+#: Variable which defines that the I2C slave is not behind a switch.
+NO_I2C_SWITCH = 5
+
+class I2CSlavesException(Exception):
+ pass
+
+
+class I2CSlave(object):
+ def __init__(self, name, bus_index, slave_address, switch_number=NO_I2C_SWITCH,
+ register_address_size=1, endianness=Endianness.LITTLE_ENDIAN,
+ should_hold_bus=False):
+ """Initialize a class which describes an I2C slave.
+
+ Args:
+ name (str): The name of the I2C slave.
+ bus_index (int): The bus number the I2C slave is connected to.
+ slave_address (int): The address of the I2C slave.
+ switch_number (int): The number of the switch the i2c salve is connected to.
+ register_address_size (int): Slave register address length (in bytes).
+ endianness (:class:`~hailo_platform.pyhailort.pyhailort.Endianness`): The endianness of the slave.
+ should_hold_bus (bool): Should hold the bus during the read.
+
+ """
+ self._name = name
+ self._bus_index = bus_index
+ self._slave_address = slave_address
+ self._switch_number = switch_number
+ self._register_address_size = register_address_size
+ self._endianness = endianness
+ self._should_hold_bus = should_hold_bus
+
+ def __repr__(self):
+ # Returning '' for the sphinx doc
+ return ''
+
+ @property
+ def name(self):
+ """Get the name of the I2C slave.
+
+ Returns:
+ str: Name of the I2C slave.
+ """
+ return self._name
+
+ @property
+ def bus_index(self):
+ """Get bus index the I2C slave is connected to.
+
+ Returns:
+ int: Index of the bus the I2C slave is connected to.
+ """
+ return self._bus_index
+
+ @property
+ def slave_address(self):
+ """Get the address of the salve.
+
+ Returns:
+ int: The address of the I2C slave.
+ """
+ return self._slave_address
+
+ @property
+ def register_address_size(self):
+ """Get the slave register address length (in bytes). This number represents how many bytes are in the
+ register address the slave can access.
+
+ Returns:
+ int: Slave register address length.
+
+ Note:
+ Pay attention to the slave endianness (:class:`~hailo_platform.pyhailort.pyhailort.Endianness`).
+ """
+ return self._register_address_size
+
+ @property
+ def switch_number(self):
+ """Get the switch number the slave is connected to.
+
+ Returns:
+ int: The number of the switch the I2C is behind.
+
+ Note:
+ If :data:`NO_I2C_SWITCH` is returned, it means the slave is not behind a switch.
+ """
+ return self._switch_number
+
+ @property
+ def endianness(self):
+ """Get the slave endianness.
+
+ Returns:
+ :class:`~hailo_platform.pyhailort.pyhailort.Endianness`: The slave endianness.
+ """
+ return self._endianness
+
+ @property
+ def should_hold_bus(self):
+ """Returns a Boolean indicating if the bus will be held while reading from the slave.
+
+ Returns:
+ bool: True if the bus would be held, otherwise False.
+ """
+ return self._should_hold_bus
+
+# DVM's
+#: Class which represents the MIPI AVDD I2C slave.
+I2C_SLAVE_MIPI_AVDD = I2CSlave("DVM_MIPI_AVDD", 0, 0x40)
+#: Class which represents the USB AVDD IO slave.
+I2C_SLAVE_USB_AVDD_IO = I2CSlave("DVM_USB_AVDD_IO", 0, 0x41)
+#: Class which represents the V_CORE slave.
+I2C_SLAVE_VDD_CORE = I2CSlave("DVM_VDD_CORE", 0, 0x42)
+#: Class which represents the VDD TOP slave.
+I2C_SLAVE_VDD_TOP = I2CSlave("DVM_VDD_TOP", 0, 0x43)
+#: Class which represents the MIPI AVDD_H I2C slave.
+I2C_SLAVE_MIPI_AVDD_H = I2CSlave("DVM_MIPI_AVDD_H", 0, 0x44)
+#: Class which represents the DVM USB AVDD IO HV slave.
+I2C_SLAVE_USB_AVDD_IO_HV = I2CSlave("DVM_USB_AVDD_IO_HV", 0, 0x45)
+#: Class which represents the DVM_VDDIO slave.
+I2C_SLAVE_VDD_IO = I2CSlave("DVM_VDD_IO", 0, 0x46)
+#: Class which represents the DVM_AVDD_H slave.
+I2C_SLAVE_AVDD_H = I2CSlave("DVM_AVDD_H", 0, 0x47)
+#: Class which represents the DVM_SDIO_VDDIO slave.
+I2C_SLAVE_SDIO_VDD_IO = I2CSlave("DVM_SDIO_VDD_IO", 0, 0x4d)
+
+#: Class which represents the DVM_SDIO_VDDIO slave.
+I2C_SLAVE_M_DOT_2_OVERCURREN_PROTECTION = I2CSlave("M_DOT_2_OVERCURREN_PROTECTION", 0, 0x40)
+
+#: Class which represents the I2S codec I2C slave.
+I2C_SLAVE_I2S_CODEC = I2CSlave("I2S_codec", 1, 0x18, should_hold_bus=True)
+
+#: Class which represents the I2C to gpio I2C slave.
+I2C_SLAVE_I2C_TO_GPIO = I2CSlave("I2C_to_GPIO", 0, 0x22)
+#: Class which represents the I2C switch slave.
+I2C_SLAVE_SWITCH = I2CSlave("I2C_SWITCH", 1, 0x70)
+
+#: Class which represents the I2C TEMP_sensor_0 slave.
+I2C_SLAVE_TEMP_SENSOR_0 = I2CSlave("TEMP_sensor_0", 0, 0x29)
+#: Class which represents the I2S TEMP_sensor_1 slave.
+I2C_SLAVE_TEMP_SENSOR_1 = I2CSlave("TEMP_sensor_1", 0, 0x2A)
+
+#: Class which represents the EEPROM I2C slave.
+I2C_SLAVE_EEPROM = I2CSlave("EEPROM", 0, 0x50, register_address_size=2,
+ endianness=Endianness.BIG_ENDIAN)
+
+# External hardware
+#: Class which represents the raspicam I2C slave.
+I2C_SLAVE_RASPICAM = I2CSlave("RaspiCam", 1, 0x36, switch_number=1, register_address_size=2,
+ endianness=Endianness.BIG_ENDIAN)
+
+I2C_SLAVE_ONSEMI_CAMERA_AR0220 = I2CSlave('Onsemi', 1, 0x10, switch_number=0, register_address_size=2,
+ endianness=Endianness.BIG_ENDIAN)
+
+I2C_SLAVE_ONSEMI_CAMERA_AS0149 = I2CSlave('Onsemi', 1, (0x90 >> 1), switch_number=0, register_address_size=2,
+ endianness=Endianness.BIG_ENDIAN)
+
+def set_i2c_switch(control_object, slave, slave_switch=None):
+ """Set the I2C switch in order to perform actions from the I2C slave.
+
+ Args:
+ control_object (:class:`~hailo_platform.pyhailort.control_object.HcpControl`): Control object
+ which communicates with the Hailo chip.
+ slave (:class:`I2CSlave`): Slave which the switch is set for.
+ slave_switch (:class:`I2CSlave`): The I2C slave for the switch it self. Defaults to
+ :data:`I2C_SLAVE_SWITCH`.
+ """
+ I2C_SWITCH_REGISTER_SIZE = 1
+ if NO_I2C_SWITCH != slave.switch_number:
+ if not slave_switch:
+ slave_switch = I2C_SLAVE_SWITCH
+
+ # Set the switch value that should be written
+ switch_value = 1 << slave.switch_number
+
+ # Write new value to the switch
+ control_object.i2c_write(slave_switch, switch_value, struct.pack('b', switch_value))
+
+ # Read data from the switch, make sure write was successful
+ read_data, = struct.unpack('b', control_object.i2c_read(slave_switch, switch_value, I2C_SWITCH_REGISTER_SIZE))
+ if read_data != switch_value:
+ raise I2CSlavesException("Switch writing has failed. Read data is different then expected %s != %s" % (
+ read_data,
+ switch_value))
--- /dev/null
+from hailo_platform.pyhailort.pyhailort import (DvmTypes, PowerMeasurementTypes, # noqa F401
+ SamplingPeriod, AveragingFactor,
+ HailoPowerMeasurementUtils, MeasurementBufferIndex, HailoRTException)
+
+# https://github.com/pybind/pybind11/issues/253
+import re
+def enum_to_dict(enum):
+ return {k: v for k, v in enum.__dict__.items() if not re.match("__(.*)", str(k)) and isinstance(v, enum)}
+
+def _get_buffer_index_enum_member(index):
+ for name, member in enum_to_dict(MeasurementBufferIndex).items():
+ if int(member) == index:
+ return member
+ raise HailoRTException("Invalid index")
--- /dev/null
+import pkg_resources
+# hailo_platform package has been renamed to hailort, but the import is still hailo_platform
+__version__ = pkg_resources.get_distribution("hailort").version
+
+import sys
+
+from argparse import ArgumentTypeError
+import numpy
+import time
+from hailo_platform.common.logger.logger import default_logger
+import gc
+import os
+
+import hailo_platform.pyhailort._pyhailort as _pyhailort
+if _pyhailort.__version__ != __version__:
+ raise ImportError("_pyhailort version ({}) does not match pyhailort version ({})".format(_pyhailort.__version__, __version__))
+
+from hailo_platform.pyhailort._pyhailort import (BootloaderVersion, TemperatureInfo, # noqa F401
+ DvmTypes, PowerMeasurementTypes, # noqa F401
+ PowerMeasurementData, NotificationId, # noqa F401
+ OvercurrentAlertState,
+ FormatOrder,
+ AveragingFactor, SamplingPeriod, MeasurementBufferIndex,
+ FormatType, WatchdogMode,
+ MipiDataTypeRx, MipiPixelsPerClock,
+ MipiClockSelection, MipiIspImageInOrder,
+ MipiIspImageOutDataType, IspLightFrequency,
+ BootSource, HailoSocketDefs, Endianness,
+ MipiInputStreamParams, SensorConfigTypes,
+ SensorConfigOpCode)
+
+BBOX_PARAMS = _pyhailort.HailoRTDefaults.BBOX_PARAMS()
+HAILO_DEFAULT_ETH_CONTROL_PORT = _pyhailort.HailoRTDefaults.HAILO_DEFAULT_ETH_CONTROL_PORT()
+INPUT_DATAFLOW_BASE_PORT = _pyhailort.HailoRTDefaults.DEVICE_BASE_INPUT_STREAM_PORT()
+OUTPUT_DATAFLOW_BASE_PORT = _pyhailort.HailoRTDefaults.DEVICE_BASE_OUTPUT_STREAM_PORT()
+PCIE_ANY_DOMAIN = _pyhailort.HailoRTDefaults.PCIE_ANY_DOMAIN()
+DEFAULT_VSTREAM_TIMEOUT_MS = 10000
+DEFAULT_VSTREAM_QUEUE_SIZE = 2
+
+class HailoSocket(object):
+ MAX_UDP_PAYLOAD_SIZE = HailoSocketDefs.MAX_UDP_PAYLOAD_SIZE()
+ MIN_UDP_PAYLOAD_SIZE = HailoSocketDefs.MIN_UDP_PAYLOAD_SIZE()
+ MAX_UDP_PADDED_PAYLOAD_SIZE = HailoSocketDefs.MAX_UDP_PADDED_PAYLOAD_SIZE()
+ MIN_UDP_PADDED_PAYLOAD_SIZE = HailoSocketDefs.MIN_UDP_PADDED_PAYLOAD_SIZE()
+ MAX_ALIGNED_UDP_PAYLOAD_SIZE_RTP = HailoSocketDefs.MAX_ALIGNED_UDP_PAYLOAD_SIZE_RTP()
+
+
+class HailoRTException(Exception):
+ pass
+
+class UdpRecvError(HailoRTException):
+ pass
+
+class InvalidProtocolVersionException(HailoRTException):
+ pass
+
+class HailoRTFirmwareControlFailedException(HailoRTException):
+ pass
+
+class HailoRTInvalidFrameException(HailoRTException):
+ pass
+
+class HailoRTUnsupportedOpcodeException(HailoRTException):
+ pass
+
+class HailoRTTimeout(HailoRTException):
+ pass
+
+class HailoRTStreamAborted(HailoRTException):
+ pass
+
+class HailoRTInvalidOperationException(HailoRTException):
+ pass
+
+class HailoRTInvalidArgumentException(HailoRTException):
+ pass
+
+class HailoRTNotFoundException(HailoRTException):
+ pass
+
+class HailoRTInvalidHEFException(HailoRTException):
+ pass
+
+class HailoRTEthException(HailoRTException):
+ pass
+
+class HailoRTPCIeDriverException(HailoRTException):
+ pass
+
+class HailoRTNetworkGroupNotActivatedException(HailoRTException):
+ pass
+
+class HailoStatusInvalidValueException(Exception):
+ pass
+
+class ExceptionWrapper(object):
+ def __enter__(self):
+ pass
+
+ def __exit__(self, exception_type, value, traceback):
+ if value is not None:
+ if exception_type is _pyhailort.HailoRTStatusException:
+ self._raise_indicative_status_exception(int(value.args[0]))
+ else:
+ raise
+
+ def _raise_indicative_status_exception(self, error_code):
+ string_error_code = get_status_message(error_code)
+ if string_error_code == "HAILO_ETH_RECV_FAILURE":
+ raise UdpRecvError("Failed to receive data")
+ if string_error_code == "HAILO_UNSUPPORTED_CONTROL_PROTOCOL_VERSION":
+ raise InvalidProtocolVersionException("HailoRT has failed because an invalid protocol version was received from device")
+ if string_error_code == "HAILO_FW_CONTROL_FAILURE":
+ raise HailoRTFirmwareControlFailedException("libhailort control operation failed")
+ if string_error_code == "HAILO_UNSUPPORTED_OPCODE":
+ raise HailoRTUnsupportedOpcodeException("HailoRT has failed because an unsupported opcode was sent to device")
+ if string_error_code == "HAILO_INVALID_FRAME":
+ raise HailoRTInvalidFrameException("An invalid frame was received")
+ if string_error_code == "HAILO_TIMEOUT":
+ raise HailoRTTimeout("Received a timeout - hailort has failed because a timeout had occurred")
+ if string_error_code == "HAILO_STREAM_ABORTED":
+ raise HailoRTStreamAborted("Stream aborted due to an external event")
+
+ if string_error_code == "HAILO_INVALID_OPERATION":
+ raise HailoRTInvalidOperationException("Invalid operation. See hailort.log for more information")
+ if string_error_code == "HAILO_INVALID_ARGUMENT":
+ raise HailoRTInvalidArgumentException("Invalid argument. See hailort.log for more information")
+ if string_error_code == "HAILO_NOT_FOUND":
+ raise HailoRTNotFoundException("Item not found. See hailort.log for more information")
+
+ if string_error_code == "HAILO_INVALID_HEF":
+ raise HailoRTInvalidHEFException("Invalid HEF. See hailort.log for more information")
+
+ if string_error_code == "HAILO_ETH_FAILURE":
+ raise HailoRTEthException("Ethernet failure. See hailort.log for more information")
+ if string_error_code == "HAILO_PCIE_DRIVER_FAIL":
+ raise HailoRTPCIeDriverException("PCIe driver failure. run 'dmesg | grep hailo' for more information")
+
+ if string_error_code == "HAILO_NETWORK_GROUP_NOT_ACTIVATED":
+ raise HailoRTNetworkGroupNotActivatedException("Network group is not activated")
+ else:
+ raise HailoRTException("libhailort failed with error: {} ({})".format(error_code, string_error_code))
+
+def get_status_message(status_code):
+ status_str = _pyhailort.get_status_message(status_code)
+ if status_str == "":
+ raise HailoStatusInvalidValueException("Value {} is not a valid status".format(status_code))
+ return status_str
+
+
+class HailoUdpScan(object):
+ def __init__(self):
+ self._logger = default_logger()
+ with ExceptionWrapper():
+ self._scan = _pyhailort.UdpScan()
+
+ def scan_devices(self, interface_name, timeout_seconds=3):
+ self._logger.info('Scanning over interface {iface}'.format(iface=interface_name))
+ timeout_milliseconds = int(timeout_seconds * 1000)
+ device_ip_addresses = self._scan.scan_devices(interface_name, timeout_milliseconds)
+ for ip in device_ip_addresses:
+ self._logger.debug("Found board at: {}".format(ip))
+ return device_ip_addresses
+
+
+class TrafficControl(object):
+ def __init__(self, ip, port, rate_bytes_per_sec):
+ if sys.platform != 'linux':
+ raise HailoRTInvalidOperationException('TrafficControl is supported only on UNIX os')
+ with ExceptionWrapper():
+ self._tc_util = _pyhailort.TrafficControlUtil(ip, port, int(rate_bytes_per_sec))
+
+ def set_rate_limit(self):
+ self._tc_util.set_rate_limit()
+
+ def reset_rate_limit(self):
+ self._tc_util.reset_rate_limit()
+
+ def get_interface_name(ip):
+ "get the interface corresponding to the given ip"
+ with ExceptionWrapper():
+ return _pyhailort.TrafficControlUtil.get_interface_name(ip)
+
+
+class ConfigureParams(object):
+
+ @staticmethod
+ def create_from_hef(hef, interface):
+ """Create configure params from HEF. These params affects the HEF configuration into a device.
+
+ Args:
+ hef (:class:`HEF`): The HEF to create the parameters from.
+ interface (:class:`HailoStreamInterface`): The stream_interface to create stream_params for.
+
+ Returns:
+ dict: The created stream params. The keys are the network_group names in the HEF. The values are default params, which can be changed.
+ """
+ with ExceptionWrapper():
+ return hef._hef.create_configure_params(interface)
+
+ @staticmethod
+ def create_mipi_inputs_from_hef(hef, output_interface, mipi_rx_id=0, data_type=MipiDataTypeRx.RAW_8,
+ img_width_pixels=1920, img_height_pixels=1080,
+ pixels_per_clock=MipiPixelsPerClock.PIXELS_PER_CLOCK_4, number_of_lanes=2,
+ clock_selection=MipiClockSelection.SELECTION_AUTOMATIC, data_rate=260, virtual_channel_index=0,
+ isp_enable=False, isp_img_in_order=MipiIspImageInOrder.GR_FIRST,
+ isp_img_out_data_type=MipiIspImageOutDataType.RGB_888, isp_crop_enable=False,
+ isp_crop_output_width_pixels=1920, isp_crop_output_height_pixels=1080,
+ isp_crop_output_width_start_offset_pixels=0, isp_crop_output_height_start_offset_pixels=0,
+ isp_test_pattern_enable=True, isp_configuration_bypass=False,
+ isp_run_time_ae_enable=True, isp_run_time_awb_enable=True, isp_run_time_adt_enable=True,
+ isp_run_time_af_enable=False, isp_run_time_calculations_interval_ms=0,
+ isp_light_frequency=IspLightFrequency.LIGHT_FREQ_50_HZ):
+ """Create configure params from HEF. These params affects the HEF configuration into a device.
+
+ .. attention:: The ISP and its features are not officially supported yet.
+
+ Args:
+ hef (:class:`HEF`): The HEF to create the parameters from.
+ output_interface (:class:`HailoStreamInterface`): The stream_interface to create output stream_params for.
+ mipi_rx_id (int): Selection of which MIPI Rx device to use.
+ data_type (:class:`~hailo_platform.pyhailort.pyhailort.MipiDataTypeRx`): The data type which will be passed over the MIPI.
+ img_width_pixels (int): The width in pixels of the image that enter to the mipi CSI. The sensor output.
+ When isp_enable and isp_crop_enable is false, is also the stream input.
+ img_height_pixels (int): The height in pixels of the image that enter to the mipi CSI. The sensor output.
+ When isp_enable and isp_crop_enable is false, is also the stream input.
+ pixels_per_clock (:class:`~hailo_platform.pyhailort.pyhailort.MipiPixelsPerClock`): Number of pixels transmitted at each
+ clock.
+ number_of_lanes (int): Number of lanes to use.
+ clock_selection (:class:`~hailo_platform.pyhailort.pyhailort.MipiClockSelection`): Selection of clock range that would be
+ used. Setting :class:`~hailo_platform.pyhailort.pyhailort.MipiClockSelection.SELECTION_AUTOMATIC` means that the
+ clock selection is calculated from the data rate.
+ data_rate (int): Rate of the passed data (MHz).
+ virtual_channel_index (int): The virtual channel index of the MIPI dphy.
+ isp_enable (bool): Enable the ISP block in the MIPI dataflow. The ISP is not supported yet.
+ isp_img_in_order (:class:`~hailo_platform.pyhailort.pyhailort.MipiIspImageInOrder`):
+ The ISP Rx bayer pixel order. Only relevant when the ISP is enabled.
+ isp_img_out_data_type (:class:`~hailo_platform.pyhailort.pyhailort.MipiIspImageOutDataType`):
+ The data type that the mipi will take out. Only relevant when the ISP is enabled.
+ isp_crop_enable (bool): Enable the crop feature in the ISP. Only relevant when the ISP is enabled.
+ isp_crop_output_width_pixels (int): The width in pixels of the output window that the ISP take out. The stream input.
+ Useful when isp_crop_enable is True. Only relevant when the ISP is enabled.
+ isp_crop_output_height_pixels (int): The height in pixels of the output window that the ISP take out. The stream input.
+ Useful when isp_crop_enable is True. Only relevant when the ISP is enabled.
+ isp_crop_output_width_start_offset_pixels (int): The width start point of the output window that the ISP take out.
+ Useful when isp_crop_enable is True. Only relevant when the ISP is enabled.
+ isp_crop_output_height_start_offset_pixels (int): The height start point of the output window that the ISP take out.
+ Useful when isp_crop_enable is True. Only relevant when the ISP is enabled.
+ isp_test_pattern_enable (bool): Enable Test pattern from the ISP. Only relevant when the ISP is enabled.
+ isp_configuration_bypass (bool): Don't load the ISP configuration file from the FLASH. Only relevant when the ISP is enabled.
+ isp_run_time_ae_enable (bool): Enable the run-time Auto Exposure in the ISP. Only relevant when the ISP is enabled.
+ isp_run_time_awb_enable (bool): Enable the run-time Auto White Balance in the ISP. Only relevant when the ISP is enabled.
+ isp_run_time_adt_enable (bool): Enable the run-time Adaptive Function in the ISP. Only relevant when the ISP is enabled.
+ isp_run_time_af_enable (bool): Enable the run-time Auto Focus in the ISP. Only relevant when the ISP is enabled.
+ isp_run_time_calculations_interval_ms (int): Interval in milliseconds between ISP run time calculations. Only relevant when the ISP is enabled.
+ isp_light_frequency (:class:`~hailo_platform.pyhailort.pyhailort.IspLightFrequency`):
+ Selection of the light frequency. This parameter varies depending on the power grid of the country where
+ the product is running. Only relevant when the ISP is enabled.
+ Returns:
+ dict: The created stream params. The keys are the network_group names in the HEF. The values are default params, which can be changed.
+ """
+
+ mipi_params = MipiInputStreamParams()
+ mipi_params.mipi_rx_id = mipi_rx_id
+ mipi_params.data_type = data_type
+ mipi_params.isp_enable = isp_enable
+ mipi_params.mipi_common_params.pixels_per_clock = pixels_per_clock
+ mipi_params.mipi_common_params.number_of_lanes = number_of_lanes
+ mipi_params.mipi_common_params.clock_selection = clock_selection
+ mipi_params.mipi_common_params.virtual_channel_index = virtual_channel_index
+ mipi_params.mipi_common_params.data_rate = data_rate
+ mipi_params.mipi_common_params.img_width_pixels = img_width_pixels
+ mipi_params.mipi_common_params.img_height_pixels = img_height_pixels
+ mipi_params.isp_params.img_in_order = isp_img_in_order
+ mipi_params.isp_params.img_out_data_type = isp_img_out_data_type
+ mipi_params.isp_params.crop_enable = isp_crop_enable
+ mipi_params.isp_params.crop_output_width_pixels = isp_crop_output_width_pixels
+ mipi_params.isp_params.crop_output_height_pixels = isp_crop_output_height_pixels
+ mipi_params.isp_params.crop_output_width_start_offset_pixels = isp_crop_output_width_start_offset_pixels
+ mipi_params.isp_params.crop_output_height_start_offset_pixels = isp_crop_output_height_start_offset_pixels
+ mipi_params.isp_params.test_pattern_enable = isp_test_pattern_enable
+ mipi_params.isp_params.configuration_bypass = isp_configuration_bypass
+ mipi_params.isp_params.run_time_ae_enable = isp_run_time_ae_enable
+ mipi_params.isp_params.run_time_awb_enable = isp_run_time_awb_enable
+ mipi_params.isp_params.run_time_adt_enable = isp_run_time_adt_enable
+ mipi_params.isp_params.run_time_af_enable = isp_run_time_af_enable
+ mipi_params.isp_params.isp_run_time_calculations_interval_ms = isp_run_time_calculations_interval_ms
+ mipi_params.isp_params.isp_light_frequency = isp_light_frequency
+ with ExceptionWrapper():
+ return hef._hef.create_configure_params_mipi_input(output_interface, mipi_params)
+
+def _get_name_as_str(name):
+ return name if name is not None else ""
+
+class HEF(object):
+ """Python representation of the Hailo Executable Format, which contains one or more compiled
+ models.
+ """
+
+ def __init__(self, hef_source):
+ """Constructor for the HEF class.
+
+ Args:
+ hef_source (str or bytes): The source from which the HEF object will be created. If the
+ source type is `str`, it is treated as a path to an hef file. If the source type is
+ `bytes`, it is treated as a buffer. Any other type will raise a ValueError.
+ """
+
+ with ExceptionWrapper():
+ if isinstance(hef_source, str):
+ self._hef = _pyhailort.Hef.create_from_file(hef_source)
+ self._path = hef_source
+ elif isinstance(hef_source, bytes):
+ self._hef = _pyhailort.Hef.create_from_buffer(hef_source)
+ self._path = None
+ else:
+ raise ValueError("HEF can only be created from a file path (str) or a buffer (bytes)")
+ self._sorted_output_names = {}
+
+ def get_networks_names(self, network_group_name=None):
+ """Gets the names of all networks in a specific network group.
+
+ Args:
+ network_group_name (str, optional): The name of the network group to access. If not given, first network_group is addressed.
+
+ Returns:
+ list of str: The names of the networks.
+ """
+ name = _get_name_as_str(network_group_name)
+ with ExceptionWrapper():
+ return self._hef.get_networks_names(name)
+
+ @property
+ def path(self):
+ """HEF file path."""
+ return self._path
+
+ def get_network_group_names(self):
+ """Get the names of the network groups in this HEF."""
+ with ExceptionWrapper():
+ return self._hef.get_network_group_names()
+
+ def get_network_groups_infos(self):
+ """Get information about the network groups in this HEF."""
+ with ExceptionWrapper():
+ return self._hef.get_network_groups_infos()
+
+ def get_input_vstream_infos(self, name=None):
+ """Get input vstreams information.
+
+ Args:
+ name (str, optional): The name of the network or network_group to access. In case network_group name is given,
+ Address all networks of the given network_group. In case not given, first network_group is addressed.
+
+ Returns:
+ list of :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with all the information objects of all input vstreams.
+ """
+ name = _get_name_as_str(name)
+ return self._hef.get_input_vstream_infos(name)
+
+ def get_output_vstream_infos(self, name=None):
+ """Get output vstreams information.
+
+ Args:
+ name (str, optional): The name of the network or network_group to access. In case network_group name is given,
+ Address all networks of the given network_group. In case not given, first network_group is addressed.
+
+ Returns:
+ list of :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with all the information objects of all output vstreams
+ """
+ name = _get_name_as_str(name)
+ return self._hef.get_output_vstream_infos(name)
+
+ def get_all_vstream_infos(self, name=None):
+ """Get input and output vstreams information.
+
+ Args:
+ name (str, optional): The name of the network or network_group to access. In case network_group name is given,
+ Address all networks of the given network_group. In case not given, first network_group is addressed.
+
+ Returns:
+ list of :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with all the information objects of all input and output vstreams
+ """
+ name = _get_name_as_str(name)
+ return self._hef.get_all_vstream_infos(name)
+
+ def get_input_stream_infos(self, name=None):
+ """Get the input low-level streams information.
+
+ Args:
+ name (str, optional): The name of the network or network_group to access. In case network_group name is given,
+ Address all networks of the given network_group. In case not given, first network_group is addressed.
+
+ Returns:
+ List of :obj:`hailo_platform.pyhailort._pyhailort.StreamInfo`: with information objects
+ of all input low-level streams.
+ """
+ name = _get_name_as_str(name)
+ return self._hef.get_input_stream_infos(name)
+
+
+ def get_output_stream_infos(self, name=None):
+ """Get the output low-level streams information of a specific network group.
+
+ Args:
+ name (str, optional): The name of the network or network_group to access. In case network_group name is given,
+ Address all networks of the given network_group. In case not given, first network_group is addressed.
+
+ Returns:
+ List of :obj:`hailo_platform.pyhailort._pyhailort.StreamInfo`: with information objects
+ of all output low-level streams.
+ """
+ name = _get_name_as_str(name)
+ return self._hef.get_output_stream_infos(name)
+
+ def get_all_stream_infos(self, name=None):
+ """Get input and output streams information of a specific network group.
+
+ Args:
+ name (str, optional): The name of the network or network_group to access. In case network_group name is given,
+ Address all networks of the given network_group. In case not given, first network_group is addressed.
+
+ Returns:
+ list of :obj:`hailo_platform.pyhailort._pyhailort.StreamInfo`: with all the information objects of all input and output streams
+ """
+ name = _get_name_as_str(name)
+ return self._hef.get_all_stream_infos(name)
+
+ def get_sorted_output_names(self, network_group_name=None):
+ """Get the names of the outputs in a network group. The order of names is determined by
+ the SDK. If the network group is not given, the first one is used.
+ """
+ if network_group_name is None:
+ network_group_name = self.get_network_group_names()[0]
+
+ if network_group_name not in self._sorted_output_names:
+ with ExceptionWrapper():
+ self._sorted_output_names[network_group_name] = self._hef.get_sorted_output_names(network_group_name)
+ return self._sorted_output_names[network_group_name]
+
+ def bottleneck_fps(self, network_group_name=None):
+ if network_group_name is None:
+ network_group_name = self.get_network_group_names()[0]
+ with ExceptionWrapper():
+ bottleneck_fps = self._hef.get_bottleneck_fps(network_group_name)
+ if bottleneck_fps == 0:
+ raise HailoRTException("bottleneck_fps is zero")
+ return bottleneck_fps
+
+ def get_udp_rates_dict(self, fps, max_supported_rate_bytes, network_group_name=None):
+ if network_group_name is None:
+ network_group_name = self.get_network_group_names()[0]
+ with ExceptionWrapper():
+ return self._hef.get_udp_rates_dict(network_group_name, fps, int(max_supported_rate_bytes))
+
+ def get_vstream_name_from_original_name(self, original_name, network_group_name=None):
+ """Get vstream name from original layer name for a specific network group.
+
+ Args:
+ original_name (str): The original layer name.
+ network_group_name (str, optional): The name of the network group to access. If not given, first network_group is addressed.
+
+ Returns:
+ str: the matching vstream name for the provided original name.
+ """
+ if network_group_name is None:
+ network_group_name = self.get_network_group_names()[0]
+ with ExceptionWrapper():
+ return self._hef.get_vstream_name_from_original_name(original_name, network_group_name)
+
+ def get_original_names_from_vstream_name(self, vstream_name, network_group_name=None):
+ """Get original names list from vstream name for a specific network group.
+
+ Args:
+ vstream_name (str): The stream name.
+ network_group_name (str, optional): The name of the network group to access. If not given, first network_group is addressed.
+
+ Returns:
+ list of str: all the matching original layers names for the provided vstream name.
+ """
+ if network_group_name is None:
+ network_group_name = self.get_network_group_names()[0]
+ with ExceptionWrapper():
+ return self._hef.get_original_names_from_vstream_name(vstream_name, network_group_name)
+
+ def get_vstream_names_from_stream_name(self, stream_name, network_group_name=None):
+ """Get vstream names list from their underlying stream name for a specific network group.
+
+ Args:
+ stream_name (str): The underlying stream name.
+ network_group_name (str, optional): The name of the network group to access. If not given, first network_group is addressed.
+
+ Returns:
+ list of str: All the matching vstream names for the provided stream name.
+ """
+ if network_group_name is None:
+ network_group_name = self.get_network_group_names()[0]
+ with ExceptionWrapper():
+ return self._hef.get_vstream_names_from_stream_name(stream_name, network_group_name)
+
+ def get_stream_names_from_vstream_name(self, vstream_name, network_group_name=None):
+ """Get stream name from vstream name for a specific network group.
+
+ Args:
+ vstream_name (str): The name of the vstreams.
+ network_group_name (str, optional): The name of the network group to access. If not given, first network_group is addressed.
+
+ Returns:
+ list of str: All the underlying streams names for the provided vstream name.
+ """
+ if network_group_name is None:
+ network_group_name = self.get_network_group_names()[0]
+ with ExceptionWrapper():
+ return self._hef.get_stream_names_from_vstream_name(vstream_name, network_group_name)
+
+
+class ConfiguredNetwork(object):
+ """Represents a network group loaded to the device."""
+
+ def __init__(self, configured_network, target, hef):
+ self._configured_network = configured_network
+ self._target = target
+ self._hef = hef
+
+ def get_networks_names(self):
+ return self._hef.get_networks_names(self.name)
+
+ def activate(self, network_group_params=None):
+ """Activate this network group in order to infer data through it.
+
+ Args:
+ network_group_params (:obj:`hailo_platform.pyhailort._pyhailort.ActivateNetworkGroupParams`, optional):
+ Network group activation params. If not given, default params will be applied,
+
+ Returns:
+ :class:`ActivatedNetworkContextManager`: Context manager that returns the activated
+ network group.
+ """
+ network_group_params = network_group_params or self.create_params()
+
+ with ExceptionWrapper():
+ return ActivatedNetworkContextManager(self,
+ self._configured_network.activate(network_group_params),
+ self._target, self._hef)
+
+ def wait_for_activation(self, timeout_ms=None):
+ """Block until activated, or until ``timeout_ms`` is passed.
+
+ Args:
+ timeout_ms (int, optional): Timeout value in milliseconds to wait for activation.
+ Defaults to ``HAILO_INFINITE``.
+
+ Raises:
+ :class:`HailoRTTimeout`: In case of timeout.
+ """
+ MAX_INT = 0x7fffffff
+ with ExceptionWrapper():
+ if timeout_ms is None:
+ timeout_ms = MAX_INT
+ return self._configured_network.wait_for_activation(timeout_ms)
+
+ @staticmethod
+ def create_params():
+ """Create activation params for network_group.
+
+ Returns:
+ :obj:`hailo_platform.pyhailort._pyhailort.ActivateNetworkGroupParams`.
+ """
+ return _pyhailort.ActivateNetworkGroupParams.default()
+
+ @property
+ def name(self):
+ return self._configured_network.get_name()
+
+ def get_output_shapes(self):
+ name_to_shape = {vstream_info.name : vstream_info.shape for vstream_info in self.get_output_vstream_infos()}
+ results = []
+ for name in self.get_sorted_output_names():
+ results.append(name_to_shape[name])
+ return tuple(results)
+
+ def get_sorted_output_names(self):
+ return self._hef.get_sorted_output_names(self.name)
+
+ def get_input_vstream_infos(self, network_name=None):
+ """Get input vstreams information.
+
+ Args:
+ network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
+
+ Returns:
+ list of :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with all the information objects of all input vstreams
+ """
+
+ name = network_name if network_name is not None else self.name
+ return self._hef.get_input_vstream_infos(name)
+
+ def get_output_vstream_infos(self, network_name=None):
+ """Get output vstreams information.
+
+ Args:
+ network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
+
+ Returns:
+ list of :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with all the information objects of all output vstreams
+ """
+
+ name = network_name if network_name is not None else self.name
+ return self._hef.get_output_vstream_infos(name)
+
+ def get_all_vstream_infos(self, network_name=None):
+ """Get input and output vstreams information.
+
+ Args:
+ network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
+
+ Returns:
+ list of :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with all the information objects of all input and output vstreams
+ """
+
+ name = network_name if network_name is not None else self.name
+ return self._hef.get_all_vstream_infos(name)
+
+ def get_input_stream_infos(self, network_name=None):
+ """Get the input low-level streams information of a specific network group.
+
+ Args:
+ network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
+
+ Returns:
+ List of :obj:`hailo_platform.pyhailort._pyhailort.StreamInfo`: with information objects
+ of all input low-level streams.
+ """
+
+ name = network_name if network_name is not None else self.name
+ return self._hef.get_input_stream_infos(name)
+
+ def get_output_stream_infos(self, network_name=None):
+ """Get the output low-level streams information of a specific network group.
+
+ Args:
+ network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
+
+ Returns:
+ List of :obj:`hailo_platform.pyhailort._pyhailort.StreamInfo`: with information objects
+ of all output low-level streams.
+ """
+
+ name = network_name if network_name is not None else self.name
+ return self._hef.get_output_stream_infos(name)
+
+ def get_all_stream_infos(self, network_name=None):
+ """Get input and output streams information of a specific network group.
+
+ Args:
+ network_name (str, optional): The name of the network to access. In case not given, all the networks in the network group will be addressed.
+
+ Returns:
+ list of :obj:`hailo_platform.pyhailort._pyhailort.StreamInfo`: with all the information objects of all input and output streams
+ """
+
+ name = network_name if network_name is not None else self.name
+ return self._hef.get_all_stream_infos(name)
+
+ def get_udp_rates_dict(self, fps, max_supported_rate_bytes):
+ with ExceptionWrapper():
+ return self._configured_network.get_udp_rates_dict(int(fps), int(max_supported_rate_bytes))
+
+ def _create_input_vstreams(self, input_vstreams_params):
+ return self._configured_network.InputVStreams(input_vstreams_params)
+
+ def _create_output_vstreams(self, output_vstreams_params):
+ return self._configured_network.OutputVStreams(output_vstreams_params)
+
+ def get_stream_names_from_vstream_name(self, vstream_name):
+ """Get stream name from vstream name for a specific network group.
+
+ Args:
+ vstream_name (str): The name of the vstreams.
+
+ Returns:
+ list of str: All the underlying streams names for the provided vstream name.
+ """
+ with ExceptionWrapper():
+ return self._hef.get_stream_names_from_vstream_name(vstream_name, self.name)
+
+ def get_vstream_names_from_stream_name(self, stream_name):
+ """Get vstream names list from their underlying stream name for a specific network group.
+
+ Args:
+ stream_name (str): The underlying stream name.
+
+ Returns:
+ list of str: All the matching vstream names for the provided stream name.
+ """
+ with ExceptionWrapper():
+ return self._hef.get_vstream_names_from_stream_name(stream_name, self.name)
+
+
+class ActivatedNetworkContextManager(object):
+ """A context manager that returns the activated network group upon enter."""
+
+ def __init__(self, configured_network, activated_network, target, hef):
+ self._configured_network = configured_network
+ self._activated_network = activated_network
+ self._target = target
+ self._hef = hef
+
+ def __enter__(self):
+ with ExceptionWrapper():
+ activated_network_group = ActivatedNetwork(self._configured_network, self._activated_network.__enter__(), self._target,
+ self._hef)
+ return activated_network_group
+
+ def __exit__(self, *args):
+ self._activated_network.__exit__(*args)
+
+
+class ActivatedNetwork(object):
+ """The network group that is currently activated for inference."""
+
+ def __init__(self, configured_network, activated_network, target, hef):
+ self._configured_network = configured_network
+ self._activated_network = activated_network
+ self._target = target
+ self._hef = hef
+ self._last_number_of_invalid_frames_read = 0
+
+ @property
+ def target(self):
+ return self._target
+
+ @property
+ def name(self):
+ return self._configured_network.name
+
+ def get_number_of_invalid_frames(self, clear=True):
+ """Returns number of invalid frames.
+
+ Args:
+ clear (bool): If set, the returned value will be the number of invalid frames read since the last call to this function.
+
+ Returns:
+ int: Number of invalid frames.
+ """
+ total_invalid_frames_count = self._activated_network.get_invalid_frames_count()
+ if clear:
+ value = total_invalid_frames_count - self._last_number_of_invalid_frames_read
+ self._last_number_of_invalid_frames_read = total_invalid_frames_count
+ return value if clear else total_invalid_frames_count
+
+ def validate_all_frames_are_valid(self):
+ """Validates that all of the frames so far are valid (no invalid frames)."""
+ number_of_invalid_frames = self.get_number_of_invalid_frames()
+ if number_of_invalid_frames != 0:
+ raise HailoRTException("There are {} invalid frames.".format(number_of_invalid_frames))
+
+ def get_sorted_output_names(self):
+ return self._hef.get_sorted_output_names(self.name)
+
+ def _get_intermediate_buffer(self, src_context_index, src_stream_index):
+ with ExceptionWrapper():
+ return self._activated_network.get_intermediate_buffer(src_context_index, src_stream_index)
+
+
+class InferVStreams(object):
+ """Pipeline that allows to call blocking inference, to be used as a context manager."""
+
+ def __init__(self, configured_net_group, input_vstreams_params, output_vstreams_params,
+ tf_nms_format=False):
+ """Constructor for the InferVStreams class.
+
+ Args:
+ configured_net_group (:class:`ConfiguredNetwork`): The configured network group for
+ which the pipeline is created.
+ input_vstreams_params (dict from str to :class:`InputVStreamParams`): Params for the
+ input vstreams in the pipeline. Only members of this dict will take part in the
+ inference.
+ output_vstreams_params (dict from str to :class:`OutputVStreamParams`): Params for the
+ output vstreams in the pipeline. Only members of this dict will take part in the
+ inference.
+ tf_nms_format (bool, optional): indicates whether the returned nms outputs should be in
+ Hailo format or TensorFlow format. Default is False (using Hailo format).
+
+ * Hailo format -- list of :obj:`numpy.ndarray`. Each element represents the
+ detections (bboxes) for the class, and its shape is
+ ``[number_of_detections, BBOX_PARAMS]``
+ * TensorFlow format -- :obj:`numpy.ndarray` of shape
+ ``[class_count, BBOX_PARAMS, detections_count]`` padded with empty bboxes.
+ """
+
+ self._logger = default_logger()
+ self._configured_net_group = configured_net_group
+ self._net_group_name = configured_net_group.name
+ self._input_vstreams_params = input_vstreams_params
+ self._output_vstreams_params = output_vstreams_params
+ self._tf_nms_format = tf_nms_format
+ self._total_time = None
+ self._hw_time = None
+ self._network_name_to_outputs = InferVStreams._get_network_to_outputs_mapping(configured_net_group)
+ self._input_name_to_network_name = InferVStreams._get_input_name_to_network_mapping(configured_net_group)
+
+ @staticmethod
+ def _get_input_name_to_network_mapping(configured_net_group):
+ input_name_to_network_mapping = {}
+ for network_name in configured_net_group.get_networks_names():
+ for input_vstream_info in configured_net_group.get_input_vstream_infos(network_name):
+ input_name_to_network_mapping[input_vstream_info.name] = network_name
+ return input_name_to_network_mapping
+
+ @staticmethod
+ def _get_network_to_outputs_mapping(configured_net_group):
+ network_to_outputs_mapping = {}
+ for network_name in configured_net_group.get_networks_names():
+ network_to_outputs_mapping[network_name] = set()
+ for output_vstream_info in configured_net_group.get_output_vstream_infos(network_name):
+ network_to_outputs_mapping[network_name].add(output_vstream_info.name)
+ return network_to_outputs_mapping
+
+ def _make_output_buffers_and_infos(self, input_data, batch_size):
+ output_buffers = {}
+ output_buffers_info = {}
+ already_seen_networks = set()
+ for input_name in input_data.keys():
+ network_name = self._input_name_to_network_name[input_name]
+ if (network_name not in already_seen_networks) :
+ already_seen_networks.add(network_name)
+ for output_name in self._network_name_to_outputs[network_name]:
+ output_buffers_info[output_name] = OutputLayerUtils(self._configured_net_group._hef, output_name, self._infer_pipeline,
+ self._net_group_name)
+ output_tensor_info = output_buffers_info[output_name].output_tensor_info
+ shape, dtype = output_tensor_info
+ output_buffers[output_name] = numpy.empty([batch_size] + list(shape), dtype=dtype)
+ return output_buffers, output_buffers_info
+
+ def __enter__(self):
+ self._infer_pipeline = _pyhailort.InferVStreams(self._configured_net_group._configured_network,
+ self._input_vstreams_params, self._output_vstreams_params)
+ return self
+
+ def infer(self, input_data):
+ """Run inference on the hardware device.
+
+ Args:
+ input_data (dict of :obj:`numpy.ndarray`): Where the key is the name of the input_layer,
+ and the value is the data to run inference on.
+
+ Returns:
+ dict: Output tensors of all output layers. The keys are outputs names and the values
+ are output data tensors as :obj:`numpy.ndarray` (or list of :obj:`numpy.ndarray` in case of nms output and tf_nms_format=False).
+ """
+
+ time_before_infer_calcs = time.time()
+ if not isinstance(input_data, dict):
+ input_stream_infos = self._configured_net_group.get_input_stream_infos()
+ if len(input_stream_infos) != 1:
+ raise Exception("when there is more than one input, the input_data should be of type dict,"
+ " mapping between each input_name, and his input_data tensor. number of inputs: {}".format(len(input_stream_infos)))
+ input_data = {input_stream_infos[0].name : input_data}
+
+ batch_size = InferVStreams._get_number_of_frames(input_data)
+ output_buffers, output_buffers_info = self._make_output_buffers_and_infos(input_data, batch_size)
+
+ for input_layer_name in input_data:
+ # TODO: Remove cast after tests are updated and are working
+ self._cast_input_data_if_needed(input_layer_name, input_data)
+ self._validate_input_data_format_type(input_layer_name, input_data)
+ self._make_c_contiguous_if_needed(input_layer_name, input_data)
+
+ with ExceptionWrapper():
+ time_before_infer = time.time()
+ self._infer_pipeline.infer(input_data, output_buffers, batch_size)
+ self._hw_time = time.time() - time_before_infer
+
+ for name, result_array in output_buffers.items():
+ is_nms = output_buffers_info[name].is_nms
+ if not is_nms:
+ continue
+ nms_shape = output_buffers_info[name].vstream_info.nms_shape
+ if self._tf_nms_format:
+ shape = [batch_size] + output_buffers_info[name].tf_nms_fomrat_shape
+ output_dtype = output_buffers_info[name].output_dtype
+ quantized_empty_bbox = output_buffers_info[name].quantized_empty_bbox
+ flat_result_array = result_array.reshape(-1)
+ output_buffers[name] = HailoRTTransformUtils.output_raw_buffer_to_nms_tf_format(flat_result_array, shape,
+ output_dtype, quantized_empty_bbox)
+ else:
+ output_buffers[name] = HailoRTTransformUtils.output_raw_buffer_to_nms_format(result_array, nms_shape.number_of_classes)
+
+ self._total_time = time.time() - time_before_infer_calcs
+ return output_buffers
+
+ def get_hw_time(self):
+ """Get the hardware device operation time it took to run inference over the last batch.
+
+ Returns:
+ float: Time in seconds.
+ """
+ return self._hw_time
+
+ def get_total_time(self):
+ """Get the total time it took to run inference over the last batch.
+
+ Returns:
+ float: Time in seconds.
+ """
+ return self._total_time
+
+ def _cast_input_data_if_needed(self, input_layer_name, input_data):
+ input_dtype = input_data[input_layer_name].dtype
+ with ExceptionWrapper():
+ input_expected_dtype = self._infer_pipeline.get_host_dtype(input_layer_name)
+ if input_dtype != input_expected_dtype:
+
+ self._logger.warning("Given input data dtype ({}) is different than inferred dtype ({}). "
+ "conversion for every frame will reduce performance".format(input_dtype,
+ input_expected_dtype))
+ input_data[input_layer_name] = input_data[input_layer_name].astype(input_expected_dtype)
+
+ def _validate_input_data_format_type(self, input_layer_name, input_data):
+ if input_layer_name not in self._input_vstreams_params:
+ return
+
+ input_data_format = self._input_vstreams_params[input_layer_name].user_buffer_format
+ input_expected_item_size = _pyhailort.get_format_data_bytes(input_data_format)
+ input_item_size = input_data[input_layer_name].dtype.itemsize
+
+ # TODO: Add distinction between float32 and int32 and others
+ if input_item_size != input_expected_item_size:
+ raise HailoRTException("{} numpy array item size is {}, not {}".format(input_layer_name,
+ input_item_size, input_expected_item_size))
+
+ @staticmethod
+ def _get_number_of_frames(input_data):
+ # Checks that all the batch-sizes of the input_data are equals for all input layers
+ if len(input_data) == 0:
+ raise ValueError("Input_data can't be empty")
+ batch_size_of_first_input = list(input_data.values())[0].shape[0]
+ for name, input_data_tensor in input_data.items():
+ if input_data_tensor.shape[0] != batch_size_of_first_input:
+ raise ValueError(
+ "The number of frames on all input_tensors should be equal! different sizes detected: {} != {}".format(
+ batch_size_of_first_input, input_data_tensor.shape[0]))
+ return batch_size_of_first_input
+
+ def _make_c_contiguous_if_needed(self, input_layer_name, input_data):
+ if not input_data[input_layer_name].flags.c_contiguous:
+ self._logger.warning("Converting {} numpy array to be C_CONTIGUOUS".format(
+ input_layer_name))
+ input_data[input_layer_name] = numpy.asarray(input_data[input_layer_name], order='C')
+
+ def __exit__(self, *args):
+ self._infer_pipeline.release()
+ return False
+
+
+class HailoRTTransformUtils(object):
+ @staticmethod
+ def get_dtype(data_bytes):
+ """Get data type from the number of bytes."""
+ if data_bytes == 1:
+ return numpy.uint8
+ elif data_bytes == 2:
+ return numpy.uint16
+ elif data_bytes == 4:
+ return numpy.float32
+ raise HailoRTException("unsupported data bytes value")
+
+ @staticmethod
+ def dequantize_output_buffer(src_buffer, dst_buffer, elements_count, quant_info):
+ """De-quantize the data in input buffer `src_buffer` and output it to the buffer `dst_buffer`
+
+ Args:
+ src_buffer (:obj:`numpy.ndarray`): The input buffer containing the data to be de-quantized.
+ The buffer's data type is the source data type.
+ dst_buffer (:obj:`numpy.ndarray`): The buffer that will contain the de-quantized data.
+ The buffer's data type is the destination data type.
+ elements_count (int): The number of elements to de-quantize. This number must not exceed 'src_buffer' or 'dst_buffer' sizes.
+ quant_info (:class:`~hailo_platform.pyhailort.pyhailort.QuantInfo`): The quantization info.
+ """
+ with ExceptionWrapper():
+ src_format_type = HailoRTTransformUtils._get_format_type(src_buffer.dtype)
+ dst_format_type = HailoRTTransformUtils._get_format_type(dst_buffer.dtype)
+ _pyhailort.dequantize_output_buffer(src_buffer, dst_buffer, src_format_type, dst_format_type, elements_count, quant_info)
+
+ @staticmethod
+ def dequantize_output_buffer_in_place(raw_buffer, dst_dtype, elements_count, quant_info):
+ """De-quantize the output buffer `raw_buffer` to data type `dst_dtype`.
+
+ Args:
+ raw_buffer (:obj:`numpy.ndarray`): The output buffer to be de-quantized. The buffer's data type is the source data type.
+ dst_dtype (:obj:`numpy.dtype`): The data type to de-quantize `raw_buffer` to.
+ elements_count (int): The number of elements to de-quantize. This number must not exceed 'raw_buffer' size.
+ quant_info (:class:`~hailo_platform.pyhailort.pyhailort.QuantInfo`): The quantization info.
+ """
+ with ExceptionWrapper():
+ src_format_type = HailoRTTransformUtils._get_format_type(raw_buffer.dtype)
+ dst_format_type = HailoRTTransformUtils._get_format_type(dst_dtype)
+ _pyhailort.dequantize_output_buffer_in_place(raw_buffer, src_format_type, dst_format_type, elements_count, quant_info)
+
+ @staticmethod
+ def quantize_input_buffer(src_buffer, dst_buffer, elements_count, quant_info):
+ """Quantize the data in input buffer `src_buffer` and output it to the buffer `dst_buffer`
+
+ Args:
+ src_buffer (:obj:`numpy.ndarray`): The input buffer containing the data to be quantized.
+ The buffer's data type is the source data type.
+ dst_buffer (:obj:`numpy.ndarray`): The buffer that will contain the quantized data.
+ The buffer's data type is the destination data type.
+ elements_count (int): The number of elements to quantize. This number must not exceed 'src_buffer' or 'dst_buffer' sizes.
+ quant_info (:class:`~hailo_platform.pyhailort.pyhailort.QuantInfo`): The quantization info.
+ """
+ with ExceptionWrapper():
+ src_format_type = HailoRTTransformUtils._get_format_type(src_buffer.dtype)
+ dst_format_type = HailoRTTransformUtils._get_format_type(dst_buffer.dtype)
+ _pyhailort.quantize_input_buffer(src_buffer, dst_buffer, src_format_type, dst_format_type, elements_count, quant_info)
+
+ @staticmethod
+ def output_raw_buffer_to_nms_tf_format(raw_output_buffer, shape, dtype, quantized_empty_bbox):
+ offset = 0
+ # We create the tf_format buffer with reversed width/features for preformance optimization
+ converted_output_buffer = numpy.empty([shape[0], shape[1], shape[3], shape[2]], dtype=dtype)
+ for frame in range(converted_output_buffer.shape[0]):
+ offset = frame * converted_output_buffer.shape[1] * (converted_output_buffer.shape[2] * converted_output_buffer.shape[3] + 1)
+ HailoRTTransformUtils.output_raw_buffer_to_nms_tf_format_single_frame(raw_output_buffer, converted_output_buffer[frame],
+ converted_output_buffer.shape[1], converted_output_buffer.shape[2], quantized_empty_bbox, offset)
+ converted_output_buffer = numpy.swapaxes(converted_output_buffer, 2, 3)
+ return converted_output_buffer
+
+ @staticmethod
+ def output_raw_buffer_to_nms_tf_format_single_frame(raw_output_buffer, converted_output_frame, number_of_classes,
+ max_bboxes_per_class, quantized_empty_bbox, offset=0):
+ for class_i in range(number_of_classes):
+ class_bboxes_amount = int(raw_output_buffer[offset])
+ offset += 1
+ if 0 != class_bboxes_amount:
+ converted_output_frame[class_i][ : class_bboxes_amount][:] = raw_output_buffer[offset : offset + (BBOX_PARAMS * class_bboxes_amount)].reshape(class_bboxes_amount, BBOX_PARAMS)
+ offset += BBOX_PARAMS * class_bboxes_amount
+ converted_output_frame[class_i][class_bboxes_amount : max_bboxes_per_class][:] = quantized_empty_bbox
+
+ @staticmethod
+ def output_raw_buffer_to_nms_format(raw_output_buffer, number_of_classes):
+ converted_output_buffer = []
+ for frame in raw_output_buffer:
+ converted_output_buffer.append(HailoRTTransformUtils.output_raw_buffer_to_nms_format_single_frame(frame, number_of_classes))
+ return converted_output_buffer
+
+ @staticmethod
+ def output_raw_buffer_to_nms_format_single_frame(raw_output_buffer, number_of_classes, offset=0):
+ converted_output_frame = []
+ for class_i in range(number_of_classes):
+ class_bboxes_amount = int(raw_output_buffer[offset])
+ offset += 1
+ if class_bboxes_amount == 0:
+ converted_output_frame.append(numpy.empty([0, BBOX_PARAMS]))
+ else:
+ converted_output_frame.append(raw_output_buffer[offset : offset + (BBOX_PARAMS * class_bboxes_amount)].reshape(
+ class_bboxes_amount, BBOX_PARAMS))
+ offset += BBOX_PARAMS * class_bboxes_amount
+ return converted_output_frame
+
+ @staticmethod
+ def _get_format_type(dtype):
+ if dtype == numpy.uint8:
+ return FormatType.UINT8
+ elif dtype == numpy.uint16:
+ return FormatType.UINT16
+ elif dtype == numpy.float32:
+ return FormatType.FLOAT32
+ raise HailoRTException("unsupported data type {}".format(dtype))
+
+class InternalEthernetDevice(object):
+ def __init__(self, address, port, response_timeout_seconds=10, max_number_of_attempts=3):
+ self.device = None
+ self._address = address
+ self._port = port
+ self._response_timeout_milliseconds = int(response_timeout_seconds * 1000)
+ self._max_number_of_attempts = max_number_of_attempts
+ with ExceptionWrapper():
+ self.device = _pyhailort.Device.create_eth(self._address, self._port,
+ self._response_timeout_milliseconds, self._max_number_of_attempts)
+
+ def __del__(self):
+ self.release()
+
+ def release(self):
+ if self.device is None:
+ return
+ with ExceptionWrapper():
+ self.device.release()
+ self.device = None
+
+
+class PcieDeviceInfo(_pyhailort.PcieDeviceInfo):
+ """Represents pcie device info, includeing domain, bus, device and function.
+ """
+
+ BOARD_LOCATION_HELP_STRING = 'Board location in the format of the command: "lspci -d 1e60: | cut -d\' \' -f1" ([<domain>]:<bus>:<device>.<func>). If not specified the first board is taken.'
+
+ def __init__(self, bus, device, func, domain=None):
+ super(PcieDeviceInfo, self).__init__()
+ self.bus = bus
+ self.device = device
+ self.func = func
+ if domain is None:
+ self.domain = PCIE_ANY_DOMAIN
+ else:
+ self.domain = domain
+
+ def __eq__(self, other):
+ return (self.domain, self.bus, self.device, self.func) == (other.domain, other.bus, other.device, other.func)
+
+ def __str__(self):
+ with ExceptionWrapper():
+ return super().__str__()
+
+ def __repr__(self):
+ return 'PcieDeviceInfo({})'.format(str(self))
+
+ @classmethod
+ def from_string(cls, board_location_str):
+ """Parse pcie device info BDF from string. The format is [<domain>]:<bus>:<device>.<func>"""
+ with ExceptionWrapper():
+ device_info = _pyhailort.PcieDeviceInfo._parse(board_location_str)
+ return PcieDeviceInfo(device_info.bus, device_info.device, device_info.func, device_info.domain)
+
+ @classmethod
+ def argument_type(cls, board_location_str):
+ """PcieDeviceInfo Argument type for argparse parsers"""
+ try:
+ return cls.from_string(board_location_str)
+ except HailoRTException:
+ raise ArgumentTypeError('Invalid device info string, format is [<domain>]:<bus>:<device>.<func>')
+
+
+class InternalPcieDevice(object):
+ def __init__(self, device_info=None):
+ self.device = None
+ if device_info is None:
+ device_info = InternalPcieDevice.scan_devices()[0]
+ self._device_info = device_info
+ with ExceptionWrapper():
+ self.device = _pyhailort.Device.create_pcie(self._device_info)
+
+ def __del__(self):
+ self.release()
+
+ def release(self):
+ if self.device is None:
+ return
+ with ExceptionWrapper():
+ self.device.release()
+ self.device = None
+
+ @staticmethod
+ def scan_devices():
+ with ExceptionWrapper():
+ return [PcieDeviceInfo(dev_info.bus, dev_info.device, dev_info.func, dev_info.domain)
+ for dev_info in _pyhailort.scan_pcie_devices()]
+
+ def create_debug_log(self):
+ return PcieDebugLog(self)
+
+ def write_memory(self, address, data):
+ with ExceptionWrapper():
+ self.device.direct_write_memory(address, data)
+
+ def read_memory(self, address, size):
+ with ExceptionWrapper():
+ return self.device.direct_read_memory(address, size)
+
+
+class PcieDebugLog(object):
+ def __init__(self, pci_device):
+ self._pcie_device = pci_device
+
+ def read(self, count, cpu_id):
+ with ExceptionWrapper():
+ return self._pcie_device.device.read_log(count, cpu_id)
+
+
+class HailoPowerMeasurementUtils(object):
+ @staticmethod
+ def return_real_sampling_period(sampling_period):
+ """Get a sampling period from the enum."""
+ SamplingPeriodDictionary = dict([
+ (SamplingPeriod.PERIOD_140us, 140),
+ (SamplingPeriod.PERIOD_204us, 204),
+ (SamplingPeriod.PERIOD_332us, 332),
+ (SamplingPeriod.PERIOD_588us, 588),
+ (SamplingPeriod.PERIOD_1100us, 1100),
+ (SamplingPeriod.PERIOD_2116us, 2116),
+ (SamplingPeriod.PERIOD_4156us, 4156),
+ (SamplingPeriod.PERIOD_8244us, 8244),
+ ])
+ return SamplingPeriodDictionary[sampling_period]
+
+ @staticmethod
+ def return_real_averaging_factor(averaging_factor):
+ """Get an averaging factor from the enum."""
+ AveragingFactorDictionary = dict([
+ (AveragingFactor.AVERAGE_1, 1),
+ (AveragingFactor.AVERAGE_4, 4),
+ (AveragingFactor.AVERAGE_16, 16),
+ (AveragingFactor.AVERAGE_64, 64),
+ (AveragingFactor.AVERAGE_128, 128),
+ (AveragingFactor.AVERAGE_256, 256),
+ (AveragingFactor.AVERAGE_512, 512),
+ (AveragingFactor.AVERAGE_1024, 1024),
+ ])
+ return AveragingFactorDictionary[averaging_factor]
+
+class HailoPowerMode(_pyhailort.PowerMode):
+ pass
+
+class HailoStreamInterface(_pyhailort.StreamInterface):
+ pass
+
+class HailoStreamDirection(_pyhailort.StreamDirection):
+ pass
+
+class HailoCpuId(_pyhailort.CpuId):
+ pass
+
+class HailoFormatFlags(_pyhailort.FormatFlags):
+ pass
+
+
+class VDevice(object):
+ """Hailo virtual device representation."""
+
+ def __init__(
+ self,
+ params=None, device_infos=None):
+
+ """Create the Hailo virtual device object.
+
+ Args:
+ params (:obj:`hailo_platform.pyhailort.pyhailort.VDeviceParams`, optional): VDevice params, call
+ :func:`VDevice.create_params` to get default params. Excludes 'device_infos'.
+ device_infos (list of :obj:`hailo_platform.pyhailort.pyhailort.PcieDeviceInfo`, optional): pcie devices infos to create VDevice from,
+ call :func:`PcieDevice.scan_devices` to get list of all available devices. Excludes 'params'.
+ """
+ gc.collect()
+ self._id = "VDevice"
+ self._params = params
+ self._device_infos = device_infos
+ if self._device_infos is not None:
+ if self._params is not None:
+ raise HailoRTException("VDevice can be created from params or device_infos. Both parameters was passed to the c'tor")
+ self._vdevice = None
+ self._loaded_network_groups = []
+ self._open_vdevice()
+
+ self._creation_pid = os.getpid()
+
+ def _open_vdevice(self):
+ if self._device_infos is not None:
+ with ExceptionWrapper():
+ self._vdevice = _pyhailort.VDevice.create_from_infos(self._device_infos)
+ else:
+ if self._params is None:
+ self._params = VDevice.create_params()
+ with ExceptionWrapper():
+ self._vdevice = _pyhailort.VDevice.create(self._params)
+
+ def __enter__(self):
+ return self
+
+ def release(self):
+ """Release the allocated resources of the device. This function should be called when working with the device not as context-manager."""
+ if self._vdevice is not None:
+ self._vdevice.release()
+ self._vdevice = None
+
+ def __exit__(self, *args):
+ self.release()
+ return False
+
+ def __del__(self):
+ self.release()
+
+ @staticmethod
+ def create_params():
+ with ExceptionWrapper():
+ return _pyhailort.VDeviceParams.default()
+
+ def configure(self, hef, configure_params_by_name={}):
+ """Configures target vdevice from HEF object.
+
+ Args:
+ hef (:class:`~hailo_platform.pyhailort.pyhailort.HEF`): HEF to configure the vdevice from
+ configure_params_by_name (dict, optional): Maps between each net_group_name to configure_params. If not provided, default params will be applied
+ """
+ if self._creation_pid != os.getpid():
+ raise HailoRTException("VDevice can only be configured from the process it was created in.")
+ with ExceptionWrapper():
+ configured_apps = self._vdevice.configure(hef._hef, configure_params_by_name)
+ configured_networks = [ConfiguredNetwork(configured_app, self, hef) for configured_app in configured_apps]
+ self._loaded_network_groups.extend(configured_networks)
+ return configured_networks
+
+ def get_physical_devices(self):
+ """Gets the underlying physical devices.
+
+ Return:
+ list of :obj:`~hailo_platform.pyhailort.hw_object.PcieDevice`: The underlying physical devices.
+ """
+ with ExceptionWrapper():
+ phys_dev_infos = self._vdevice.get_physical_devices_infos()
+ pythonic_dev_infos = [PcieDeviceInfo(dev_info.bus, dev_info.device, dev_info.func, dev_info.domain)
+ for dev_info in phys_dev_infos]
+
+ from hailo_platform.pyhailort.hw_object import PcieDevice
+ return [PcieDevice(info) for info in pythonic_dev_infos]
+
+ def get_physical_devices_infos(self):
+ """Gets the physical devices infos.
+
+ Return:
+ list of :obj:`~hailo_platform.pyhailort.pyhailort.PcieDeviceInfo`: The underlying physical devices infos.
+ """
+ with ExceptionWrapper():
+ return self._vdevice.get_physical_devices_infos()
+
+
+class InputVStreamParams(object):
+ """Parameters of an input virtual stream (host to device)."""
+
+ @staticmethod
+ def make(configured_network, quantized=True, format_type=None, timeout_ms=None, queue_size=None, network_name=None):
+ """Create input virtual stream params from a configured network group. These params determine the format of the
+ data that will be fed into the network group.
+
+ Args:
+ configured_network (:class:`ConfiguredNetwork`): The configured network group for which
+ the params are created.
+ quantized (bool): Whether the data fed into the chip is already quantized. True means
+ the data is already quantized. False means it's HailoRT's responsibility to quantize
+ (scale) the data. Defaults to True.
+ format_type (:class:`~hailo_platform.pyhailort.pyhailort.FormatType`): The
+ default format type of the data for all input virtual streams. If quantized is False,
+ the default is :attr:`~hailo_platform.pyhailort.pyhailort.FormatType.FLOAT32`. Otherwise,
+ the default is :attr:`~hailo_platform.pyhailort.pyhailort.FormatType.AUTO`,
+ which means the data is fed in the same format expected by the device (usually
+ uint8).
+ timeout_ms (int): The default timeout in milliseconds for all input virtual streams.
+ Defaults to DEFAULT_VSTREAM_TIMEOUT_MS. In case of timeout, :class:`HailoRTTimeout` will be raised.
+ queue_size (int): The pipeline queue size. Defaults to DEFAULT_VSTREAM_QUEUE_SIZE.
+ network_name (str): Network name of the requested virtual stream params.
+ If not passed, all the networks in the network group will be addressed.
+
+ Returns:
+ dict: The created virtual streams params. The keys are the vstreams names. The values are the
+ params.
+ """
+ if format_type is None:
+ if not quantized:
+ format_type = FormatType.FLOAT32
+ else:
+ format_type = FormatType.AUTO
+ if timeout_ms is None:
+ timeout_ms = DEFAULT_VSTREAM_TIMEOUT_MS
+ if queue_size is None:
+ queue_size = DEFAULT_VSTREAM_QUEUE_SIZE
+ name = network_name if network_name is not None else configured_network.name
+ with ExceptionWrapper():
+ return configured_network._hef._hef.get_input_vstreams_params(name, quantized,
+ format_type, timeout_ms, queue_size)
+
+ @staticmethod
+ def make_from_network_group(configured_network, quantized=True, format_type=None, timeout_ms=None, queue_size=None, network_name=None):
+ """Create input virtual stream params from a configured network group. These params determine the format of the
+ data that will be fed into the network group.
+
+ Args:
+ configured_network (:class:`ConfiguredNetwork`): The configured network group for which
+ the params are created.
+ quantized (bool): Whether the data fed into the chip is already quantized. True means
+ the data is already quantized. False means it's HailoRT's responsibility to quantize
+ (scale) the data. Defaults to True.
+ format_type (:class:`~hailo_platform.pyhailort.pyhailort.FormatType`): The
+ default format type of the data for all input virtual streams. If quantized is False,
+ the default is :attr:`~hailo_platform.pyhailort.pyhailort.FormatType.FLOAT32`. Otherwise,
+ the default is :attr:`~hailo_platform.pyhailort.pyhailort.FormatType.AUTO`,
+ which means the data is fed in the same format expected by the device (usually
+ uint8).
+ timeout_ms (int): The default timeout in milliseconds for all input virtual streams.
+ Defaults to DEFAULT_VSTREAM_TIMEOUT_MS. In case of timeout, :class:`HailoRTTimeout` will be raised.
+ queue_size (int): The pipeline queue size. Defaults to DEFAULT_VSTREAM_QUEUE_SIZE.
+ network_name (str): Network name of the requested virtual stream params.
+ If not passed, all the networks in the network group will be addressed.
+
+ Returns:
+ dict: The created virtual streams params. The keys are the vstreams names. The values are the
+ params.
+ """
+ return InputVStreamParams.make(configured_network, quantized, format_type, timeout_ms, queue_size, network_name)
+
+
+class OutputVStreamParams(object):
+ """Parameters of an output virtual stream (device to host)."""
+
+ @staticmethod
+ def make(configured_network, quantized=True, format_type=None, timeout_ms=None, queue_size=None, network_name=None):
+ """Create output virtual stream params from a configured network group. These params determine the format of the
+ data that will be fed into the network group.
+
+ Args:
+ configured_network (:class:`ConfiguredNetwork`): The configured network group for which
+ the params are created.
+ quantized (bool): Whether the data fed into the chip is already quantized. True means
+ the data is already quantized. False means it's HailoRT's responsibility to quantize
+ (scale) the data. Defaults to True.
+ format_type (:class:`~hailo_platform.pyhailort.pyhailort.FormatType`): The
+ default format type of the data for all output virtual streams. If quantized is False,
+ the default is :attr:`~hailo_platform.pyhailort.pyhailort.FormatType.FLOAT32`. Otherwise,
+ the default is :attr:`~hailo_platform.pyhailort.pyhailort.FormatType.AUTO`,
+ which means the data is fed in the same format expected by the device (usually
+ uint8).
+ timeout_ms (int): The default timeout in milliseconds for all output virtual streams.
+ Defaults to DEFAULT_VSTREAM_TIMEOUT_MS. In case of timeout, :class:`HailoRTTimeout` will be raised.
+ queue_size (int): The pipeline queue size. Defaults to DEFAULT_VSTREAM_QUEUE_SIZE.
+ network_name (str): Network name of the requested virtual stream params.
+ If not passed, all the networks in the network group will be addressed.
+
+ Returns:
+ dict: The created virtual streams params. The keys are the vstreams names. The values are the
+ params.
+ """
+ if format_type is None:
+ if not quantized:
+ format_type = FormatType.FLOAT32
+ else:
+ format_type = FormatType.AUTO
+ if timeout_ms is None:
+ timeout_ms = DEFAULT_VSTREAM_TIMEOUT_MS
+ if queue_size is None:
+ queue_size = DEFAULT_VSTREAM_QUEUE_SIZE
+ name = network_name if network_name is not None else configured_network.name
+ with ExceptionWrapper():
+ return configured_network._hef._hef.get_output_vstreams_params(name, quantized,
+ format_type, timeout_ms, queue_size)
+
+ @staticmethod
+ def make_from_network_group(configured_network, quantized=True, format_type=None, timeout_ms=None, queue_size=None, network_name=None):
+ """Create output virtual stream params from a configured network group. These params determine the format of the
+ data that will be fed into the network group.
+
+ Args:
+ configured_network (:class:`ConfiguredNetwork`): The configured network group for which
+ the params are created.
+ quantized (bool): Whether the data fed into the chip is already quantized. True means
+ the data is already quantized. False means it's HailoRT's responsibility to quantize
+ (scale) the data. Defaults to True.
+ format_type (:class:`~hailo_platform.pyhailort.pyhailort.FormatType`): The
+ default format type of the data for all output virtual streams. If quantized is False,
+ the default is :attr:`~hailo_platform.pyhailort.pyhailort.FormatType.FLOAT32`. Otherwise,
+ the default is :attr:`~hailo_platform.pyhailort.pyhailort.FormatType.AUTO`,
+ which means the data is fed in the same format expected by the device (usually
+ uint8).
+ timeout_ms (int): The default timeout in milliseconds for all output virtual streams.
+ Defaults to DEFAULT_VSTREAM_TIMEOUT_MS. In case of timeout, :class:`HailoRTTimeout` will be raised.
+ queue_size (int): The pipeline queue size. Defaults to DEFAULT_VSTREAM_QUEUE_SIZE.
+ network_name (str): Network name of the requested virtual stream params.
+ If not passed, all the networks in the network group will be addressed.
+
+ Returns:
+ dict: The created virtual streams params. The keys are the vstreams names. The values are the
+ params.
+ """
+ return OutputVStreamParams.make(configured_network, quantized, format_type, timeout_ms, queue_size, network_name)
+
+ @staticmethod
+ def make_groups(configured_network, quantized=True, format_type=None, timeout_ms=None, queue_size=None):
+ """Create output virtual stream params from a configured network group. These params determine the format of the
+ data that will be fed into the network group. The params groups are splitted with respect to their underlying streams for multi process usges.
+
+ Args:
+ configured_network (:class:`ConfiguredNetwork`): The configured network group for which
+ the params are created.
+ quantized (bool): Whether the data fed into the chip is already quantized. True means
+ the data is already quantized. False means it's HailoRT's responsibility to quantize
+ (scale) the data. Defaults to True.
+ format_type (:class:`~hailo_platform.pyhailort.pyhailort.FormatType`): The
+ default format type of the data for all output virtual streams. If quantized is False,
+ the default is :attr:`~hailo_platform.pyhailort.pyhailort.FormatType.FLOAT32`. Otherwise,
+ the default is :attr:`~hailo_platform.pyhailort.pyhailort.FormatType.AUTO`,
+ which means the data is fed in the same format expected by the device (usually
+ uint8).
+ timeout_ms (int): The default timeout in milliseconds for all output virtual streams.
+ Defaults to DEFAULT_VSTREAM_TIMEOUT_MS. In case of timeout, :class:`HailoRTTimeout` will be raised.
+ queue_size (int): The pipeline queue size. Defaults to DEFAULT_VSTREAM_QUEUE_SIZE.
+
+ Returns:
+ list of dicts: Each element in the list represent a group of params, where the keys are the vstreams names, and the values are the
+ params. The params groups are splitted with respect to their underlying streams for multi process usges.
+ """
+ all_params = OutputVStreamParams.make(configured_network, quantized=quantized, format_type=format_type, timeout_ms=timeout_ms, queue_size=queue_size)
+ low_level_streams_names = [stream_info.name for stream_info in configured_network.get_output_stream_infos()]
+ stream_name_to_vstream_names = {stream_name: configured_network.get_vstream_names_from_stream_name(stream_name) for stream_name in low_level_streams_names}
+ results = []
+ for low_level_stream_name, vstream_names in stream_name_to_vstream_names.items():
+ params_group = {}
+ for vstream_name in vstream_names:
+ # Vstreams that were already seen should not be added to another params_group
+ if all_params[vstream_name] is not None:
+ params_group[vstream_name] = all_params[vstream_name]
+ all_params[vstream_name] = None
+ if 0 < len(params_group):
+ results.append(params_group)
+ return results
+
+
+class InputVStream(object):
+ """Represents a single virtual stream in the host to device direction."""
+
+ def __init__(self, send_object):
+ self._send_object = send_object
+ self._input_dtype = self._send_object.dtype
+
+ @property
+ def shape(self):
+ return self._send_object.shape
+
+ @property
+ def dtype(self):
+ return self._send_object.dtype
+
+ @property
+ def name(self):
+ return self._send_object.info.name
+
+ @property
+ def network_name(self):
+ return self._send_object.info.network_name
+
+ def send(self, input_data):
+ """Send frames to inference.
+
+ Args:
+ input_data (:obj:`numpy.ndarray`): Data to run inference on.
+ """
+
+ if input_data.dtype != self._input_dtype:
+ input_data = input_data.astype(self._input_dtype)
+
+ if not input_data.flags.c_contiguous:
+ logger = default_logger()
+ logger.warning("Warning - Converting input numpy array to be C_CONTIGUOUS")
+ input_data = numpy.asarray(input_data, order='C')
+
+ batch_number = 0
+ batch_size = 1
+ while batch_number < input_data.shape[0]:
+ data = input_data[batch_number:batch_number + batch_size]
+ with ExceptionWrapper():
+ self._send_object.send(data)
+ batch_number += batch_size
+
+ def flush(self):
+ """Blocks until there are no buffers in the input VStream pipeline."""
+ with ExceptionWrapper():
+ self._send_object.flush()
+
+ @property
+ def info(self):
+ with ExceptionWrapper():
+ return self._send_object.info
+
+class InputVStreams(object):
+ """Input vstreams pipelines that allows to send data, to be used as a context manager."""
+
+ def __init__(self, configured_network, input_vstreams_params):
+ """Constructor for the InputVStreams class.
+
+ Args:
+ configured_network (:class:`ConfiguredNetwork`): The configured network group for which the pipeline is created.
+ input_vstreams_params (dict from str to :class:`InputVStreamParams`): Params for the input vstreams in the pipeline.
+ """
+ self._configured_network = configured_network
+ self._input_vstreams_params = input_vstreams_params
+ self._vstreams = {}
+
+ def __enter__(self):
+ self._input_vstreams_holder = self._configured_network._create_input_vstreams(self._input_vstreams_params)
+ self._input_vstreams_holder.__enter__()
+ for name, vstream in self._input_vstreams_holder.get_all_inputs().items():
+ self._vstreams[name] = InputVStream(vstream)
+ return self
+
+ def get(self, name=None):
+ """Return a single input vstream by its name.
+
+ Args:
+ name (str): The vstream name. If name=None and there is a single input vstream, that single (:class:`InputVStream`) will be returned.
+ Otherwise, if name=None and there are multiple input vstreams, an exception will be thrown.
+
+ Returns:
+ :class:`InputVStream`: The (:class:`InputVStream`) that corresponds to the given name.
+ """
+ if name is None:
+ if len(self._vstreams) != 1:
+ raise HailoRTException("There is no single input vStream. You must give a name")
+ name = list(self._vstreams.keys())[0]
+ return self._vstreams[name]
+
+ def clear(self):
+ """Clears the vstreams' pipeline buffers."""
+ with ExceptionWrapper():
+ self._input_vstreams_holder.clear()
+
+ def __exit__(self, *args):
+ self._input_vstreams_holder.__exit__(*args)
+ return False
+
+ def __iter__(self):
+ return iter(self._vstreams.values())
+
+class OutputLayerUtils(object):
+ def __init__(self, hef, vstream_name, pipeline, net_group_name=""):
+ self._hef = hef
+ self._vstream_info = self._get_vstream_info(net_group_name, vstream_name)
+
+ if isinstance(pipeline, (_pyhailort.InferVStreams)):
+ self._user_buffer_format = pipeline.get_user_buffer_format(vstream_name)
+ self._output_shape = pipeline.get_shape(vstream_name)
+ else:
+ self._user_buffer_format = pipeline.get_user_buffer_format()
+ self._output_shape = pipeline.shape
+
+ self._is_nms = (self._user_buffer_format.order == FormatOrder.HAILO_NMS)
+
+ if self._is_nms:
+ self._quantized_empty_bbox = numpy.asarray([0] * BBOX_PARAMS, dtype=self.output_dtype)
+ if not (self._user_buffer_format.flags & _pyhailort.FormatFlags.QUANTIZED):
+ HailoRTTransformUtils.dequantize_output_buffer_in_place(self._quantized_empty_bbox, self.output_dtype,
+ BBOX_PARAMS, self._vstream_info.quant_info)
+
+ @property
+ def output_dtype(self):
+ return _pyhailort.get_dtype(self._user_buffer_format.type)
+
+ @property
+ def output_shape(self):
+ return self._output_shape
+
+ @property
+ def vstream_info(self):
+ return self._vstream_info
+
+ @property
+ def output_tensor_info(self):
+ return self.output_shape, self.output_dtype
+
+ @property
+ def is_nms(self):
+ return self._is_nms
+
+ @property
+ def quantized_empty_bbox(self):
+ if not self.is_nms:
+ raise HailoRTException("Requested NMS info for non-NMS layer")
+ return self._quantized_empty_bbox
+
+ def _get_vstream_info(self, net_group_name, vstream_name):
+ output_vstream_infos = self._hef.get_output_vstream_infos(net_group_name)
+ for info in output_vstream_infos:
+ if info.name == vstream_name:
+ return info
+ raise HailoRTException("No vstream matches the given name {}".format(vstream_name))
+
+ @property
+ def tf_nms_fomrat_shape(self):
+ if not self.is_nms:
+ raise HailoRTException("Requested NMS info for non-NMS layer")
+ nms_shape = self._vstream_info.nms_shape
+ return [nms_shape.number_of_classes, BBOX_PARAMS,
+ nms_shape.max_bboxes_per_class]
+
+class OutputVStream(object):
+ """Represents a single output virtual stream in the device to host direction."""
+
+ def __init__(self, configured_network, recv_object, name, tf_nms_format=False, net_group_name=""):
+ self._recv_object = recv_object
+ self._output_layer_utils = OutputLayerUtils(configured_network._hef, name, self._recv_object, net_group_name)
+ self._output_dtype = self._output_layer_utils.output_dtype
+ self._vstream_info = self._output_layer_utils._vstream_info
+ self._output_tensor_info = self._output_layer_utils.output_tensor_info
+ self._is_nms = self._output_layer_utils.is_nms
+ if self._is_nms:
+ self._quantized_empty_bbox = self._output_layer_utils.quantized_empty_bbox
+ self._tf_nms_format = tf_nms_format
+
+ @property
+ def shape(self):
+ return self._recv_object.shape
+
+ @property
+ def dtype(self):
+ return self._recv_object.dtype
+
+ @property
+ def name(self):
+ return self._vstream_info.name
+
+ @property
+ def network_name(self):
+ return self._vstream_info.network_name
+
+ def recv(self):
+ """Receive frames after inference.
+
+ Returns:
+ :obj:`numpy.ndarray`: The output of the inference for a single frame. The returned
+ tensor does not include the batch dimension.
+ In case of nms output and tf_nms_format=False, returns list of :obj:`numpy.ndarray`.
+ """
+ result_array = None
+ with ExceptionWrapper():
+ result_array = self._recv_object.recv()
+
+ if self._is_nms:
+ nms_shape = self._vstream_info.nms_shape
+ if self._tf_nms_format:
+ nms_results_tesnor = result_array
+ # We create the tf_format buffer with reversed width/features for preformance optimization
+ shape = self._output_layer_utils.tf_nms_fomrat_shape
+ result_array = numpy.empty([shape[0], shape[2], shape[1]], dtype=self._output_dtype)
+ HailoRTTransformUtils.output_raw_buffer_to_nms_tf_format_single_frame(nms_results_tesnor, result_array,
+ nms_shape.number_of_classes,
+ nms_shape.max_bboxes_per_class, self._quantized_empty_bbox)
+ result_array = numpy.swapaxes(result_array, 1, 2)
+ else:
+ result_array = HailoRTTransformUtils.output_raw_buffer_to_nms_format_single_frame(result_array,
+ nms_shape.number_of_classes)
+ return result_array
+
+ @property
+ def info(self):
+ with ExceptionWrapper():
+ return self._recv_object.info
+
+class OutputVStreams(object):
+ """Output virtual streams pipelines that allows to receive data, to be used as a context manager."""
+
+ def __init__(self, configured_network, output_vstreams_params, tf_nms_format=False):
+ """Constructor for the OutputVStreams class.
+
+ Args:
+ configured_network (:class:`ConfiguredNetwork`): The configured network group for which
+ the pipeline is created.
+ output_vstreams_params (dict from str to :class:`OutputVStreamParams`): Params for the
+ output vstreams in the pipeline.
+ tf_nms_format (bool, optional): indicates whether the returned nms outputs should be in
+ Hailo format or TensorFlow format. Default is False (using Hailo format).
+
+ * Hailo format -- list of :obj:`numpy.ndarray`. Each element represents th
+ detections (bboxes) for the class, and its shape is
+ ``[number_of_detections, BBOX_PARAMS]``
+ * TensorFlow format -- :obj:`numpy.ndarray` of shape
+ ``[class_count, BBOX_PARAMS, detections_count]`` padded with empty bboxes.
+ """
+ self._configured_network = configured_network
+ self._net_group_name = configured_network.name
+ self._output_vstreams_params = output_vstreams_params
+ self._output_tensor_info = {}
+ self._tf_nms_format = tf_nms_format
+ self._vstreams = {}
+
+ def __enter__(self):
+ self._output_vstreams_holder = self._configured_network._create_output_vstreams(self._output_vstreams_params)
+ self._output_vstreams_holder.__enter__()
+ for name, vstream in self._output_vstreams_holder.get_all_outputs().items():
+ self._vstreams[name] = OutputVStream(self._configured_network, vstream, name,
+ tf_nms_format=self._tf_nms_format, net_group_name=self._net_group_name)
+ return self
+
+ def get(self, name=None):
+ """Return a single output vstream by its name.
+
+ Args:
+ name (str): The vstream name. If name=None and there is a single output vstream, that single (:class:`OutputVStream`) will be returned.
+ Otherwise, if name=None and there are multiple output vstreams, an exception will be thrown.
+
+ Returns:
+ :class:`OutputVStream`: The (:class:`OutputVStream`) that corresponds to the given name.
+ """
+ if name is None:
+ if len(self._vstreams) != 1:
+ raise HailoRTException("There is no single output vStream. You must give a name")
+ name = list(self._vstreams.keys())[0]
+ return self._vstreams[name]
+
+ def clear(self):
+ """Clears the vstreams' pipeline buffers."""
+ with ExceptionWrapper():
+ self._output_vstreams_holder.clear()
+
+ def __exit__(self, *args):
+ self._output_vstreams_holder.__exit__(*args)
+ return False
+
+ def __iter__(self):
+ return iter(self._vstreams.values())
\ No newline at end of file
+++ /dev/null
-from hailo_platform.common.tools.cmd_utils.base_utils import HailortCliUtil
-
-class BenchmarkCommandCLI(HailortCliUtil):
- def __init__(self, parser):
- super().__init__(parser, 'benchmark')
+++ /dev/null
-#!/usr/bin/env python
-
-import argparse
-import argcomplete
-import sys
-
-import hailo_platform
-from hailo_platform.common.tools.cmd_utils.base_utils import HailortCliUtil, Helper, HailortCliUtilError
-from hailo_platform.tools.firmware.update_firmware import FWUpdaterCLI
-from hailo_platform.tools.firmware.update_second_stage import SSBUpdaterCLI
-from hailo_platform.tools.udp_rate_limiter import UDPRateLimiterCLI
-from hailo_platform.tools.fw_control import ControlCommandCLI, ScanCommandCLI, LoggerCommandCLI, MeasurePowerCommandCLI
-from hailo_platform.tools.run_command import RunCommandCLI
-from hailo_platform.tools.infer_cli import InferCLI
-from hailo_platform.tools.firmware.sensor_config import SensorConfigCommandCLI
-from hailo_platform.tools.firmware.configure_firmware import FWConfigCommandCLI
-from hailo_platform.tools.benchmark_command import BenchmarkCommandCLI
-
-
-# Note: PlatformCommands are external dependencies in phase2-sdk/demos repo; don't change!
-class PlatformCommands:
- INVALID_COMMAND_EXIT_CODE = 1
-
- PLATFORM_COMMANDS = {
- 'fw-update': ('Firmware update tool', FWUpdaterCLI),
- 'ssb-update': ('Second stage boot update tool', SSBUpdaterCLI),
- 'fw-config': ('Firmware configuration tool', FWConfigCommandCLI),
- 'udp-limiter': ('UDP rate limitation tool', UDPRateLimiterCLI),
- 'udp': ('Alias to udp-limiter', UDPRateLimiterCLI),
- 'fw-control': ('Useful firmware control operations', ControlCommandCLI),
- 'fw-logger': ('Download fw logs to a file', LoggerCommandCLI),
- 'scan': ('Scans for devices (Ethernet or PCIE)', ScanCommandCLI),
- 'broadcast': ('Scans for devices on a given interface (alias to \'hailo scan\')', ScanCommandCLI),
- 'sensor-config': ('Sensor configuration tool', SensorConfigCommandCLI),
- 'infer': ('Run a compiled network - infer command is deprecated and will be removed in a future release. Please use \'hailo run\' instead.', InferCLI),
- 'run': ('Run a compiled network', RunCommandCLI),
- 'benchmark': ('Measure basic performance on compiled network', BenchmarkCommandCLI),
- 'measure-power': ('Measures power consumption', MeasurePowerCommandCLI),
- }
-
- def __init__(self):
- self.parser = argparse.ArgumentParser(description=self._get_description())
- self.subparsers = self.parser.add_subparsers(help='Hailo utilities aimed to help with everything you need')
- self.COMMANDS = {}
- self.COMMANDS.update(type(self).PLATFORM_COMMANDS)
-
- try:
- # If sdk_client is importable - add its commands to this tool
- from hailo_sdk_client.tools.cmd_utils.main import ClientCommands
- self.COMMANDS.update(ClientCommands.SDK_COMMANDS)
- except ImportError:
- pass
-
- @staticmethod
- def _get_description():
- return 'Hailo Platform SW v{} command line utilities'.format(hailo_platform.__version__)
-
- def run(self):
- argv = sys.argv[1:]
- return self._run(argv)
-
- # Dependency injection for testing
- def _run(self, argv):
- self.COMMANDS['help'] = ('show the list of commands', Helper(self.COMMANDS))
- # Create the commands and let them set the arguments
- commands = {}
- for command_name, (help_, command_class) in self.COMMANDS.items():
- commands[command_name] = command_class(self.subparsers.add_parser(command_name, help=help_))
-
- argcomplete.autocomplete(self.parser)
- # HailortCliUtil commands are parsed by hailortcli:
- # * argv from after the command name are forwarded to hailortcli.
- # * E.g. calling `hailo udp-limiter arg1 arg2` will result in the call `commands['udp-limiter'].run(['arg1', 'arg2'])`.
- # Inturn, this will create the process `hailortcli udp-rate-limiter arg1 arg2` (via the UDPRateLimiterCLI class).
- # In order to support this, we first check if the first argument in argv is the name of a HailortCliUtil class.
- # If so, we'll pass the arguments to the HailortCliUtil, otherwise we parse with argparse as usual.
- if len(argv) == 0:
- self.parser.print_help()
- return self.INVALID_COMMAND_EXIT_CODE
-
- command_name = argv[0]
- if (command_name in commands) and isinstance(commands[command_name], HailortCliUtil):
- # HailortCliUtil just passes the rest of the argv to hailortcli
- try :
- return commands[command_name].run(argv[1:])
- except HailortCliUtilError as e:
- print('\n'+ str(e))
- return
-
- # This isn't a HailortCliUtil commnad, parse with argparse
- args = self.parser.parse_args(argv)
- # Due to a bug in Python's handling of subparsers, we cannot require a sub-command using argparse. A manual
- # check is performed here so we can print out a proper message. (https://bugs.python.org/issue9253)
- if not vars(args):
- self.parser.print_help()
- return self.INVALID_COMMAND_EXIT_CODE
-
- # The commands themself, set the default func.
- return args.func(args)
-
-
-def main():
- a = PlatformCommands()
- return a.run()
-
-
-if __name__ == '__main__':
- main()
+++ /dev/null
-#!/usr/bin/env python
-
-"""Parses a configuration file that contains user or board configurations.
-"""
-from hailo_platform.common.tools.cmd_utils.base_utils import HailortCliUtil
-
-class FWConfigCommandCLI(HailortCliUtil):
- """CLI tool for changing the FW configuration (User Config)"""
- def __init__(self, parser):
- super().__init__(parser, 'fw-config')
-
-class BoardConfigCommandCLI(HailortCliUtil):
- """CLI tool for changing the FW configuration (Board Config)"""
- def __init__(self, parser):
- super().__init__(parser, 'board-config')
+++ /dev/null
-{
- "network":
- {
- "static_netmask": "255.255.255.0",
- "should_use_dhcp": false,
- "mac_address": "80:00:DE:AD:BE:EF"
- },
- "system":
- {
- "name": "Hailo-8",
- "supported_aspm_states": "ASPM L1 ONLY",
- "temperature_throttling_enable": true
- }
-}
+++ /dev/null
-#!/usr/bin/env python
-
-"""Parses a configuration file that contains the definitions of possible user configurations
- Availabe in the firmware.
-"""
-
-from builtins import object
-import json
-
-from abc import ABCMeta
-from collections import OrderedDict
-from future.utils import with_metaclass
-
-
-
-class ConfigSyntaxException(Exception):
- """Raised when there is a syntax error in the configuration file."""
- pass
-
-
-class UnsupportedConfigVersionException(Exception):
- """Raised when the version of the configuration file is not supported."""
- pass
-
-
-class ConfigFormattingException(Exception):
- """Raised when there is a formatting error in the firmware's configuration."""
- pass
-
-class ConfigDeserializationException(Exception):
- """Raised when there is an error while parsing a binary configuration."""
- pass
-
-
-class ConfigLine(with_metaclass(ABCMeta, object)):
- """An abstract config line class. Implements logic that is shared between a few types
- of configuration lines.
- """
-
- def __init__(self, config_name, config_id):
- """Initializes a new ConfigLine object.
-
- Args:
- config_name(str): Name defined for the configuration in the line.
- config_id(int): Config ID (the integer representing the config).
- """
- self._name = None
- self.name = config_name
- self._id = config_id
-
- @property
- def name(self):
- """Returns:
- str: Name of the category.
- """
- return self._name
-
- @name.setter
- def name(self, config_name):
- if not (config_name.isalnum() or config_name[0].isalpha()):
- raise ConfigSyntaxException('Configuration name must be alphanumeric (with a first '
- 'alphabetical character) received: {}'.format(
- config_name))
- self._name = config_name.lower()
-
- @property
- def id_value(self):
- """Returns:
- int: Value of the entry's ID.
- """
- return self._id
-
-
-class ConfigEntry(ConfigLine):
- """A configuration entry."""
-
- _PRIMITIVE_TYPES = {
- 1: 'int8_t',
- 2: 'int16_t',
- 4: 'int32_t'}
-
- def __init__(self, entry_name, entry_id, category_id, size, length, sign, deserializer, length_before_serialization=None):
- """Initializes a new ConfigEntry object.
-
- Args:
- entry_name(str): Entry name.
- entry_id(int): Entry ID (the integer representing the entry). (Should be 0-65535)
- category_id(int): ID of the category that contains this entry. (Should be 0-65535)
- size(int): Size of the entry in bytes. Only primitive sizes are supported.
- length(int): Length of the entry, defined as an array if different than 0.
- sign(bool): Is the primitive signed.
- deserializer(str): The formatter to use when deserializing the entry.
- length_before_serialization(int): Length of the entry before serialization, should be given only if this length
- is different than size
- """
- super(ConfigEntry, self).__init__(entry_name, entry_id)
- self._category_id = category_id
- if size not in self._PRIMITIVE_TYPES:
- raise ConfigSyntaxException(
- 'Unsupported entry size. Supported sizes {}.'.format(list(self._PRIMITIVE_TYPES.keys())))
- self._size = size
- self._length = length
- self._sign = sign
- self._deserializer = deserializer
- if length_before_serialization is None:
- self._length_before_serialization = size
- else:
- self._length_before_serialization = length_before_serialization
-
- @property
- def deserializer(self):
- """Returns:
- str: The formatter to use when deserializing the entry.
- """
- return self._deserializer
-
- @property
- def primitive_type(self):
- """Returns:
- str: The string representing the primitve C type of the entry.
- """
- var_type = self._PRIMITIVE_TYPES[self._size]
- if not self._sign:
- var_type = 'u{}'.format(var_type)
- return var_type
-
- @property
- def category_id(self):
- """Returns:
- int: Entry id value.
- """
- return self._category_id
-
- @property
- def length(self):
- """Returns:
- int: Length of the entry, if this is different than zero, then the entry is an array.
- """
- return self._length
-
- @property
- def total_size(self):
- """Returns:
- int: Entry's total size in bytes.
- """
- if self._length == 0:
- return self._size
- else:
- return self._length * self._size
-
- @property
- def length_before_serialization(self):
- """Returns:
- int: The length of the entry before serialization
- """
- return self._length_before_serialization
-
-class ConfigCategory(ConfigLine):
- """A configuration category that contains multiple configuration IDs"""
-
- def __init__(self, category_name, category_id):
- """Initializes a new ConfigCategory object.
-
- Args:
- category_name(str): Category name.
- category_id(int): Category ID (the integer representing the category).
- """
- super(ConfigCategory, self).__init__(category_name, category_id)
- self._config_entries = OrderedDict()
- self._current_entry_id = 0
-
- def append(self, entry_name, size, deserialize_as, length=0, sign=False, length_before_serialization=None):
- """Adds a new entry to the category
-
- Args:
- entry_name(str): Name of the appended configuration entry.
- size(int): Size of the entry in bytes. Only primitive sizes are supported.
- length(int): Length of the entry, defined as an array if different than 0.
- sign(bool): Is the primitive signed.
- deserialize_as(str): The formatter to use when deserializing the entry.
- """
- config_entry = ConfigEntry(
- entry_name,
- self._current_entry_id,
- self._id,
- size,
- length,
- sign,
- deserialize_as,
- length_before_serialization)
- self._config_entries[config_entry.name] = config_entry
- self._current_entry_id += 1
-
- @property
- def entries(self):
- """Returns:
- list of :obj:`ConfigEntry`: The entries in this category object.
- """
- return self._config_entries
-
- def __getitem__(self, key):
- """Returns:
- int: The ID value of the requested entry key.
- """
- return self._config_entries[key.lower()]
-
-
-class FirmwareConfig(object):
- """This class wraps the configuration file that defines the firmware user config."""
- _SUPPORTED_VERSION = [0]
- _MAGIC_NUMBER = 0x1FF6A40B
-
- def __init__(self, config_path):
- """Initializes a new FirmwareConfig object.
-
- Args:
- config_path(str): Path to a configuration file.
- """
- config_file = open(config_path, 'r')
- config_json = json.load(config_file, object_pairs_hook=OrderedDict)
- self._current_category = None
- self._next_category_id = 0
- self._categories = OrderedDict()
- self._parse_config_json(config_json)
-
- def _parse_config_json(self, config_json):
- """Parses a json dictionary containing the configuration and assigns it to the
- object attributes.
-
- Args:
- config_json(dict of str): A dictionary containing the configration file's content.
- """
- try:
- version = config_json['version']
- except KeyError:
- raise ConfigSyntaxException('Error: Version definition not found.')
- if version not in self._SUPPORTED_VERSION:
- raise UnsupportedConfigVersionException('Unsupported version: {}.\n'
- 'Supported versions: {}'.format(
- version, self._SUPPORTED_VERSION))
- self.version = version
-
- try:
- categories = config_json['categories']
- except KeyError:
- raise ConfigSyntaxException('Error: Categories definition not found.')
-
- for i, category in enumerate(categories):
- category_object = ConfigCategory(category, i)
- try:
- entries = config_json['categories'][category]['entries']
- except KeyError:
- raise ConfigSyntaxException('Error: Category {} does not contain entries.'.format(
- category))
- for entry in entries:
- category_object.append(entry, **entries[entry])
- self._categories[category_object.name] = category_object
-
- @property
- def supported_version(self):
- """Returns:
- list of int: A list containing the supported configuration version.
- """
- return self._SUPPORTED_VERSION
-
- @property
- def magic(self):
- """Returns:
- int: Firmware configuration magic number value.
- """
- return self._MAGIC_NUMBER
-
- @property
- def categories(self):
- """Returns:
- list of :obj:`ConfigCategory`: List of configuration categories contained in the
- firmware configuration.
- """
- return self._categories
-
- def __getitem__(self, key):
- """Returns:
- :class:`sdk_client.hailo_sdk_client.tools.firmware.ConfigCategory: The category
- corresponding to the requested key.
- """
- return self._categories[key]
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-"""Parses a configuration file that contains camera sensor configurations in the FW.
-"""
-from hailo_platform.common.tools.cmd_utils.base_utils import HailortCliUtil
-
-class SensorConfigCommandCLI(HailortCliUtil):
- def __init__(self, parser):
- super().__init__(parser, 'sensor-config')
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from hailo_platform.common.tools.cmd_utils.base_utils import HailortCliUtil
-
-
-class FWUpdaterCLI(HailortCliUtil):
- """Cli tool for firmware updates"""
- def __init__(self, parser):
- super().__init__(parser, 'fw-update')
+++ /dev/null
-#!/usr/bin/env python
-
-from hailo_platform.common.tools.cmd_utils.base_utils import HailortCliUtil
-
-
-class SSBUpdaterCLI(HailortCliUtil):
- """Cli tool for second stage boot updates"""
- def __init__(self, parser):
- super().__init__(parser, 'ssb-update')
+++ /dev/null
-#!/usr/bin/env python
-from hailo_platform.common.tools.cmd_utils.base_utils import HailortCliUtil
-
-
-class ScanCommandCLI(HailortCliUtil):
- def __init__(self, parser):
- super().__init__(parser, 'scan')
-
-
-class ControlCommandCLI(HailortCliUtil):
- def __init__(self, parser):
- super().__init__(parser, 'fw-control')
-
-class LoggerCommandCLI(HailortCliUtil):
- def __init__(self, parser):
- super().__init__(parser, 'fw-logger')
-
-class MeasurePowerCommandCLI(HailortCliUtil):
- def __init__(self, parser):
- super().__init__(parser, 'measure-power')
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env python
+from __future__ import print_function
+from builtins import object
+import subprocess
+
+from hailo_platform.common.logger.logger import default_logger
+
+
+class CmdUtilsBaseUtilError(Exception):
+ pass
+
+
+class HailortCliUtilError(CmdUtilsBaseUtilError):
+ pass
+
+
+# Note: CmdUtilsBaseUtil and CmdUtilsBaseUtilError are external dependencies in phase2-sdk/demos repo; don't change!
+class CmdUtilsBaseUtil(object):
+ def __init__(self, args_parser):
+ pass
+
+
+class Helper(CmdUtilsBaseUtil):
+ def __init__(self, commands):
+ self._commands = commands
+
+ def __call__(self, parser):
+ parser.set_defaults(func=self.run)
+
+ def run(self, args):
+ for command_name, (help_, _) in self._commands.items():
+ print("{} - {}".format(command_name, help_))
+
+
+class HailortCliUtil(CmdUtilsBaseUtil):
+ def __init__(self, args_parser, command):
+ self._command = command
+ self._logger = default_logger()
+
+ @classmethod
+ def _run_hailortcli(cls, binary_path, command, command_args):
+ cmd_args = [binary_path, command] + command_args
+
+ process = subprocess.Popen(cmd_args)
+ try:
+ _ = process.communicate()
+ return process.returncode
+ except KeyboardInterrupt:
+ process.terminate()
+ raise HailortCliUtilError('hailo has been interrupted by the user')
+
+ def run(self, argv):
+ hailortcli_cmd = 'hailortcli'
+ self._logger.info('(hailo) Running command \'{}\' with \'hailortcli\''.format(self._command))
+ return self._run_hailortcli(hailortcli_cmd, self._command, argv)
--- /dev/null
+{
+ "_comment":
+ [
+ "This file defines the available fields of the firmwares config. It is not used to serialize any data.",
+ "WARNING! DO NOT CHANGE THE ORDER OF THE DEFINITIONS AS IT WILL CHANGE THEIR GENERATED VALUES!"
+ ],
+ "version": 0,
+ "categories":
+ {
+ "network":
+ {
+ "entries":
+ {
+ "should_use_dhcp": {"size": 1, "deserialize_as": "bool"},
+ "mac_address": {"size": 1, "length": 6, "deserialize_as": "mac_address"},
+ "static_ip_address": {"size": 4, "deserialize_as": "ipv4"},
+ "static_gw_address": {"size": 4, "deserialize_as": "ipv4"},
+ "static_netmask": {"size": 4, "deserialize_as": "ipv4"},
+ "rx_pause_frames_enable": {"size": 1, "deserialize_as": "bool"}
+ }
+ },
+ "system":
+ {
+ "entries":
+ {
+ "name": {"size": 1, "length": 32, "deserialize_as": "str"},
+ "app_watchdog_enable": {"size": 1, "deserialize_as": "bool"},
+ "app_watchdog_cycles": {"size": 4, "deserialize_as": "int"},
+ "core_watchdog_enable": {"size": 1, "deserialize_as": "bool"},
+ "core_watchdog_cycles": {"size": 4, "deserialize_as": "int"},
+ "watchdog_mode" : {"size": 1, "deserialize_as": "watchdog_mode"},
+ "max_neural_network_core_clock_rate": {"size": 4, "deserialize_as": "clock_frequency"},
+ "supported_aspm_states": {"size": 1, "deserialize_as": "supported_aspm_states"},
+ "bus_0_i2c_speed": {"size": 1, "deserialize_as": "i2c_speed"},
+ "bus_1_i2c_speed": {"size": 1, "deserialize_as": "i2c_speed"},
+ "bus_2_i2c_speed": {"size": 1, "deserialize_as": "i2c_speed"},
+ "bus_3_i2c_speed": {"size": 1, "deserialize_as": "i2c_speed"},
+ "supported_aspm_l1_substates": {"size": 1, "deserialize_as": "supported_aspm_l1_substates"},
+ "overcurrent_parameters_source": {"size": 1, "deserialize_as": "overcurrent_parameters_source"},
+ "overcurrent_monitoring_red_threshold": {"size": 4, "deserialize_as": "int"},
+ "overcurrent_conversion_time_microseconds": {"size": 4, "deserialize_as": "conversion_time"},
+ "temperature_parameters_source": {"size": 1, "deserialize_as": "temperature_parameters_source"},
+ "temperature_red_threshold": {"size": 1, "deserialize_as": "int"},
+ "temperature_red_hysteresis_threshold": {"size": 1, "deserialize_as": "int"},
+ "temperature_orange_threshold": {"size": 1, "deserialize_as": "int"},
+ "temperature_orange_hysteresis_threshold": {"size": 1, "deserialize_as": "int"},
+ "temperature_throttling_enable": {"size": 1, "deserialize_as": "bool"},
+ "overcurrent_monitoring_orange_threshold_enable": {"size": 1, "deserialize_as": "bool"}
+ }
+ },
+ "control":
+ {
+ "entries":
+ {
+ "udp_port": {"size": 2, "deserialize_as": "int"}
+ }
+ },
+ "d2h_event":
+ {
+ "entries":
+ {
+ "host_udp_port": {"size": 2, "deserialize_as": "int"},
+ "src_udp_port": {"size": 2, "deserialize_as": "int"},
+ "host_ip_address": {"size": 4, "deserialize_as": "ipv4"},
+ "connection_type": {"size": 1, "deserialize_as": "bool"}
+ }
+ },
+ "logger":
+ {
+ "entries":
+ {
+ "send_via_pci": {"size": 1, "deserialize_as": "bool"},
+ "send_via_uart": {"size": 1, "deserialize_as": "bool"},
+ "logger_level": {"size": 4, "deserialize_as": "logger_level"}
+ }
+ }
+ }
+}
+
--- /dev/null
+{
+ "network":
+ {
+ "static_netmask": "255.255.255.0",
+ "should_use_dhcp": false,
+ "mac_address": "80:00:DE:AD:BE:EF"
+ },
+ "system":
+ {
+ "name": "Hailo-8",
+ "supported_aspm_states": "ASPM L1 ONLY",
+ "temperature_throttling_enable": true
+ }
+}
--- /dev/null
+#!/usr/bin/env python
+from enum import Enum
+
+from hailo_platform.tools.hailocli.base_utils import CmdUtilsBaseUtil
+from hailo_platform.pyhailort.hw_object import EthernetDevice, PcieDevice
+from hailo_platform.common.logger.logger import default_logger
+from hailo_platform.pyhailort.pyhailort import PcieDeviceInfo, InternalPcieDevice
+
+logger = default_logger()
+
+class HailoCLITargets(Enum):
+ udp = 'udp'
+ pcie = 'pcie'
+
+
+class HailoDeviceCmdUtil(CmdUtilsBaseUtil):
+ """
+ Base class for any cmd utility that use a specific hailo device
+ """
+ def __init__(self, args_parser, set_target_args=True):
+ super().__init__(args_parser)
+ self._parser = args_parser
+ if set_target_args:
+ self.add_target_args(args_parser)
+
+ def get_target(self, args):
+ self.validate_args(args)
+ target_type = self.get_target_type(args)
+ if target_type == HailoCLITargets.udp.value:
+ return EthernetDevice(args.ip)
+ else:
+ try:
+ return PcieDevice(device_info=args.board_location)
+ except Exception as e:
+ logger.error('Internal PCIe error (No PCIe device connected?)')
+ logger.error('Error code: {}'.format(e))
+ raise
+
+ def get_target_type(self, args):
+ if args.target is not None:
+ return args.target
+
+ if args.ip is not None:
+ # If IP is given, we assume that the target is udp
+ return HailoCLITargets.udp.value
+
+ # Otherwise the default target is pcie
+ return HailoCLITargets.pcie.value
+
+
+ def validate_args(self, args):
+ if args.target == HailoCLITargets.udp.value:
+ if not args.ip:
+ self._parser.error('When using --target udp, you must supply --ip')
+ if args.board_location:
+ self._parser.error("When using --target udp, you must not supply --board-location")
+
+ if args.board_location:
+ all_devices = InternalPcieDevice.scan_devices()
+ if args.board_location not in all_devices:
+ self._parser.error('Device {} does not appear on your host, please run `hailo scan -d pcie` to see all available devices'
+ .format(args.board_location))
+
+ def add_target_args(self, args_parser):
+ args_parser.add_argument('--target', type=str, choices=[t.value for t in HailoCLITargets],
+ default=None, help='Device type to use')
+ args_parser.add_argument('--ip', type=str, default=None, help='IP address of the target (udp)')
+ args_parser.add_argument('-s', '--board-location', help=PcieDeviceInfo.BOARD_LOCATION_HELP_STRING,
+ type=PcieDeviceInfo.argument_type)
--- /dev/null
+
+from hailo_platform.tools.hailocli.base_utils import HailortCliUtil
+
+"""
+ HailoRTCLI matching commands in Hailo-CLI tool.
+"""
+
+class BenchmarkCommandCLI(HailortCliUtil):
+ def __init__(self, parser):
+ super().__init__(parser, 'benchmark')
+
+
+class FWConfigCommandCLI(HailortCliUtil):
+ """CLI tool for changing the FW configuration (User Config)"""
+ def __init__(self, parser):
+ super().__init__(parser, 'fw-config')
+
+
+class BoardConfigCommandCLI(HailortCliUtil):
+ """CLI tool for changing the FW configuration (Board Config)"""
+ def __init__(self, parser):
+ super().__init__(parser, 'board-config')
+
+
+class ScanCommandCLI(HailortCliUtil):
+ def __init__(self, parser):
+ super().__init__(parser, 'scan')
+
+
+class ControlCommandCLI(HailortCliUtil):
+ def __init__(self, parser):
+ super().__init__(parser, 'fw-control')
+
+
+class LoggerCommandCLI(HailortCliUtil):
+ def __init__(self, parser):
+ super().__init__(parser, 'fw-logger')
+
+
+class MeasurePowerCommandCLI(HailortCliUtil):
+ def __init__(self, parser):
+ super().__init__(parser, 'measure-power')
+
+
+class RunCommandCLI(HailortCliUtil):
+ def __init__(self, parser):
+ super().__init__(parser, 'run')
+
+
+class SensorConfigCommandCLI(HailortCliUtil):
+ def __init__(self, parser):
+ super().__init__(parser, 'sensor-config')
+
+
+class FWUpdaterCLI(HailortCliUtil):
+ """Cli tool for firmware updates"""
+ def __init__(self, parser):
+ super().__init__(parser, 'fw-update')
+
+
+class SSBUpdaterCLI(HailortCliUtil):
+ """Cli tool for second stage boot updates"""
+ def __init__(self, parser):
+ super().__init__(parser, 'ssb-update')
+
+
+class UDPRateLimiterCLI(HailortCliUtil):
+ """CLI tool for UDP rate limitation."""
+ def __init__(self, parser):
+ super().__init__(parser, 'udp-rate-limiter')
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env python
+
+import argparse
+import argcomplete
+import sys
+
+import hailo_platform
+from hailo_platform.tools.hailocli.base_utils import HailortCliUtil, Helper, HailortCliUtilError
+from hailo_platform.tools.hailocli.hailocli_commands import (FWUpdaterCLI, SSBUpdaterCLI, ControlCommandCLI, ScanCommandCLI,
+ LoggerCommandCLI, MeasurePowerCommandCLI, RunCommandCLI, SensorConfigCommandCLI,
+ FWConfigCommandCLI, BenchmarkCommandCLI, UDPRateLimiterCLI)
+
+# Note: PlatformCommands are external dependencies in phase2-sdk/demos repo; don't change!
+class PlatformCommands:
+ INVALID_COMMAND_EXIT_CODE = 1
+
+ PLATFORM_COMMANDS = {
+ 'fw-update': ('Firmware update tool', FWUpdaterCLI),
+ 'ssb-update': ('Second stage boot update tool', SSBUpdaterCLI),
+ 'fw-config': ('Firmware configuration tool', FWConfigCommandCLI),
+ 'udp-limiter': ('UDP rate limitation tool', UDPRateLimiterCLI),
+ 'udp': ('Alias to udp-limiter', UDPRateLimiterCLI),
+ 'fw-control': ('Useful firmware control operations', ControlCommandCLI),
+ 'fw-logger': ('Download fw logs to a file', LoggerCommandCLI),
+ 'scan': ('Scans for devices (Ethernet or PCIE)', ScanCommandCLI),
+ 'sensor-config': ('Sensor configuration tool', SensorConfigCommandCLI),
+ 'run': ('Run a compiled network', RunCommandCLI),
+ 'benchmark': ('Measure basic performance on compiled network', BenchmarkCommandCLI),
+ 'measure-power': ('Measures power consumption', MeasurePowerCommandCLI),
+ }
+
+ def __init__(self):
+ self.parser = argparse.ArgumentParser(description=self._get_description())
+ self.subparsers = self.parser.add_subparsers(help='Hailo utilities aimed to help with everything you need')
+ self.COMMANDS = {}
+ self.COMMANDS.update(type(self).PLATFORM_COMMANDS)
+
+ try:
+ # If sdk_client is importable - add its commands to this tool
+ from hailo_sdk_client.tools.cmd_utils.main import ClientCommands
+ self.COMMANDS.update(ClientCommands.SDK_COMMANDS)
+ except ImportError:
+ pass
+
+ @staticmethod
+ def _get_description():
+ return 'Hailo Platform SW v{} command line utilities'.format(hailo_platform.__version__)
+
+ def run(self):
+ argv = sys.argv[1:]
+ return self._run(argv)
+
+ # Dependency injection for testing
+ def _run(self, argv):
+ self.COMMANDS['help'] = ('show the list of commands', Helper(self.COMMANDS))
+ # Create the commands and let them set the arguments
+ commands = {}
+ for command_name, (help_, command_class) in self.COMMANDS.items():
+ commands[command_name] = command_class(self.subparsers.add_parser(command_name, help=help_))
+
+ argcomplete.autocomplete(self.parser)
+ # HailortCliUtil commands are parsed by hailortcli:
+ # * argv from after the command name are forwarded to hailortcli.
+ # * E.g. calling `hailo udp-limiter arg1 arg2` will result in the call `commands['udp-limiter'].run(['arg1', 'arg2'])`.
+ # Inturn, this will create the process `hailortcli udp-rate-limiter arg1 arg2` (via the UDPRateLimiterCLI class).
+ # In order to support this, we first check if the first argument in argv is the name of a HailortCliUtil class.
+ # If so, we'll pass the arguments to the HailortCliUtil, otherwise we parse with argparse as usual.
+ if len(argv) == 0:
+ self.parser.print_help()
+ return self.INVALID_COMMAND_EXIT_CODE
+
+ command_name = argv[0]
+ if (command_name in commands) and isinstance(commands[command_name], HailortCliUtil):
+ # HailortCliUtil just passes the rest of the argv to hailortcli
+ try :
+ return commands[command_name].run(argv[1:])
+ except HailortCliUtilError as e:
+ print('\n'+ str(e))
+ return
+
+ # This isn't a HailortCliUtil commnad, parse with argparse
+ args = self.parser.parse_args(argv)
+ # Due to a bug in Python's handling of subparsers, we cannot require a sub-command using argparse. A manual
+ # check is performed here so we can print out a proper message. (https://bugs.python.org/issue9253)
+ if not vars(args):
+ self.parser.print_help()
+ return self.INVALID_COMMAND_EXIT_CODE
+
+ # The commands themself, set the default func.
+ return args.func(args)
+
+
+def main():
+ a = PlatformCommands()
+ return a.run()
+
+
+if __name__ == '__main__':
+ main()
+++ /dev/null
-from enum import Enum
-
-from hailo_platform.common.tools.cmd_utils.hailo_device_utils import HailoDeviceCmdUtil
-from hailo_platform.common.logger.logger import default_logger
-from hailo_platform.tools.run_command import RunCommandCLI
-from hailo_platform.common.tools.cmd_utils.base_utils import HailortCliUtilError
-
-logger = default_logger()
-
-class InferModes(Enum):
- simple = 'simple'
- performance = 'performance'
-
-class InferCLI(HailoDeviceCmdUtil):
- def __init__(self, parser):
- super().__init__(parser, set_target_args=False)
- self._hailortcli_run_command = RunCommandCLI(parser)
- self._parser = parser
- subparsers = parser.add_subparsers(title="Inference mode", dest="mode")
- subparsers.required = True
- simple_parser =subparsers.add_parser(InferModes.simple.value, help="'simple' mode is unsupported, please use 'hailo run' instead")
- simple_parser.add_argument('--input-data-path', type=str, default=None,
- help="unsupported argument.")
- simple_parser.add_argument('--results-path', type=str, default=None,
- help='Unsupported argument.')
- simple_parser.add_argument('--config-path', type=str, required=True, help='Path to config HEF to infer with')
- performance_parser = subparsers.add_parser(InferModes.performance.value,
- help="infer command is deprecated and will be removed in a future release, please use 'hailo run' instead")
- performance_parser.add_argument('--config-path', type=str, required=True,
- help='Path to config HEF to infer with')
- self.add_target_args(performance_parser)
- performance_parser.add_argument('-t', '--streaming-time', type=float, default=10.0, help='For how long to stream in performance mode')
- performance_parser.add_argument('--streaming-mode',
- choices=['hw-only', 'full'],
- default='full',
- help='Whether to skip pre-infer and post-infer steps on host (hw-only) or do them (full)')
- parser.set_defaults(func=self.run)
-
- def run(self, args):
- if InferModes[args.mode] == InferModes.simple:
- logger.info("mode simple is deprecated please use \'hailo run\' instead.\n"
- ".npz and .npy format are unsupported, use binary file instead, you can use the following example:\n"
- "\'hailo run --input-files [Input file path] [hef]\'.\n"
- "for more information use \'hailo run --help\'.")
- else:
- self.validate_args(args)
- argv = [args.config_path, "-t", str(int(args.streaming_time)), '-m', "streaming" if args.streaming_mode == 'full' else 'hw_only']
- if args.target == 'udp':
- argv += ['-d', args.target, '--ip', args.ip]
- try:
- self._hailortcli_run_command.run(argv)
- except HailortCliUtilError as e:
- print('\n'+ str(e))
- return
+++ /dev/null
-from hailo_platform.common.tools.cmd_utils.base_utils import HailortCliUtil
-
-class RunCommandCLI(HailortCliUtil):
- def __init__(self, parser):
- super().__init__(parser, 'run')
from builtins import object
-from hailo_platform.common.tools.cmd_utils.base_utils import HailortCliUtil
-from hailo_platform.drivers.hailort.pyhailort import ConfiguredNetwork, HEF, TrafficControl, INPUT_DATAFLOW_BASE_PORT
+from hailo_platform.pyhailort.pyhailort import ConfiguredNetwork, HEF, TrafficControl, INPUT_DATAFLOW_BASE_PORT
DEFAULT_MAX_KBPS = 850e3
DEFAULT_MAX_KBPS_PAPRIKA_B0 = 160e3
"""RateLimiterWrapper constructor.
Args:
- configured_network_group (:class:`~hailo_platform.drivers.hailort.pyhailort.ConfiguredNetwork`): The
+ configured_network_group (:class:`~hailo_platform.pyhailort.pyhailort.ConfiguredNetwork`): The
target network_group.
fps (int): Frame rate.
fps_factor (float): Safety factor by which to multiply the calculated UDP rate.
port = stream_info.sys_index + INPUT_DATAFLOW_BASE_PORT
results[port] = input_rates[stream_info.name] / BYTES_IN_Kbits
- return results
-
-
-class UDPRateLimiterCLI(HailortCliUtil):
- """CLI tool for UDP rate limitation."""
- def __init__(self, parser):
- super().__init__(parser, 'udp-rate-limiter')
+ return results
\ No newline at end of file
+++ /dev/null
-from __future__ import print_function
-from builtins import object
-import threading
-
-
-class Watchdog(object):
- def __init__(self, queues_to_close, timeout=20):
- self.timeout = timeout
- self._queues_to_close = queues_to_close
- self._t = None
-
- def do_expire(self):
- for queue_to_close in self._queues_to_close:
- queue_to_close.close()
-
- def _expire(self):
- print("\nWatchdog expire")
- self.do_expire()
-
- def start(self):
- if self.timeout is not None:
- self._t = threading.Timer(self.timeout, self._expire)
- self._t.start()
- else:
- self._t = None
-
- def stop(self):
- if self._t is not None:
- self._t.cancel()
-
- def refresh(self):
- self.stop()
- self.start()
--- /dev/null
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "# Python inference tutorial\n",
+ "\n",
+ "This tutorial will walk you through the inference process.\n",
+ "\n",
+ "**Requirements:**\n",
+ "\n",
+ "* Run the notebook inside the Python virtual environment: ```source hailo_virtualenv/bin/activate```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Standalone hardware deployment\n",
+ "\n",
+ "The standalone flow allows direct access to the HW, developing applications directly on top of Hailo\n",
+ "core HW, using HailoRT. This way we can use the Hailo hardware without Tensorflow, and\n",
+ "even without the Hailo SDK (after the HEF is built).\n",
+ "\n",
+ "An HEF is Hailo’s binary format for neural networks. The HEF files contain:\n",
+ "\n",
+ "* Target HW configuration\n",
+ "* Weights\n",
+ "* Metadata for HailoRT (e.g. input/output scaling)\n",
+ "\n",
+ "First create the desired target object. In our example we use the Hailo-8 PCIe interface:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "from multiprocessing import Process\n",
+ "from hailo_platform import (HEF, PcieDevice, HailoStreamInterface, InferVStreams, ConfigureParams,\n",
+ " InputVStreamParams, OutputVStreamParams, InputVStreams, OutputVStreams, FormatType)\n",
+ "\n",
+ "# The target can be used as a context manager (\"with\" statement) to ensure it's released on time.\n",
+ "# Here it's avoided for the sake of simplicity\n",
+ "target = PcieDevice()\n",
+ "\n",
+ "# Loading compiled HEFs to device:\n",
+ "model_name = 'resnet_v1_18'\n",
+ "hef_path = '../hefs/{}.hef'.format(model_name) \n",
+ "hef = HEF(hef_path)\n",
+ " \n",
+ "# Configure network groups\n",
+ "configure_params = ConfigureParams.create_from_hef(hef=hef, interface=HailoStreamInterface.PCIe)\n",
+ "network_groups = target.configure(hef, configure_params)\n",
+ "network_group = network_groups[0]\n",
+ "network_group_params = network_group.create_params()\n",
+ "\n",
+ "# Create input and output virtual streams params\n",
+ "# Quantized argument signifies whether or not the incoming data is already quantized.\n",
+ "# Data is quantized by HailoRT if and only if quantized == False .\n",
+ "input_vstreams_params = InputVStreamParams.make(network_group, quantized=False, format_type=FormatType.FLOAT32)\n",
+ "output_vstreams_params = OutputVStreamParams.make(network_group, quantized=True, format_type=FormatType.UINT8)\n",
+ "\n",
+ "# Define dataset params\n",
+ "input_vstream_info = hef.get_input_vstream_infos()[0]\n",
+ "output_vstream_info = hef.get_output_vstream_infos()[0]\n",
+ "image_height, image_width, channels = input_vstream_info.shape\n",
+ "num_of_images = 10\n",
+ "low, high = 2, 20\n",
+ "\n",
+ "# Generate random dataset\n",
+ "dataset = np.random.randint(low, high, (num_of_images, image_height, image_width, channels)).astype(np.float32)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Running hardware inference\n",
+ "Infer the model and then display the output shape:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Infer \n",
+ "with InferVStreams(network_group, input_vstreams_params, output_vstreams_params) as infer_pipeline:\n",
+ " input_data = {input_vstream_info.name: dataset}\n",
+ " with network_group.activate(network_group_params):\n",
+ " infer_results = infer_pipeline.infer(input_data)\n",
+ " print('Stream output shape is {}'.format(infer_results[output_vstream_info.name].shape))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Streaming inference\n",
+ "\n",
+ "This section shows how to run streaming inference using multiple processes in Python.\n",
+ "\n",
+ "We will not use infer. Instead we will use a send and receive model.\n",
+ "The send function and the receive function will run in different processes."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Define the send and receive functions:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def send(configured_network, num_frames):\n",
+ " vstreams_params = InputVStreamParams.make(configured_network)\n",
+ " configured_network.wait_for_activation(1000)\n",
+ " with InputVStreams(configured_network, vstreams_params) as vstreams:\n",
+ " vstream_to_buffer = {vstream: np.ndarray([1] + list(vstream.shape), dtype=vstream.dtype) for vstream in vstreams}\n",
+ " for _ in range(num_frames):\n",
+ " for vstream, buff in vstream_to_buffer.items():\n",
+ " vstream.send(buff)\n",
+ "\n",
+ "def recv(configured_network, vstreams_params, num_frames):\n",
+ " configured_network.wait_for_activation(1000)\n",
+ " with OutputVStreams(configured_network, vstreams_params) as vstreams:\n",
+ " for _ in range(num_frames):\n",
+ " for vstream in vstreams:\n",
+ " data = vstream.recv()\n",
+ "\n",
+ "def recv_all(configured_network, num_frames):\n",
+ " vstreams_params_groups = OutputVStreamParams.make_groups(configured_network)\n",
+ " recv_procs = []\n",
+ " for vstreams_params in vstreams_params_groups:\n",
+ " proc = Process(target=recv, args=(configured_network, vstreams_params, num_frames))\n",
+ " proc.start()\n",
+ " recv_procs.append(proc)\n",
+ " for proc in recv_procs:\n",
+ " proc.join()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Define the amount of frames to stream, define the processes, create the target and run processes:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Define the amount of frames to stream\n",
+ "num_of_frames = 1000\n",
+ "\n",
+ "send_process = Process(target=send, args=(network_group, num_of_frames))\n",
+ "recv_process = Process(target=recv_all, args=(network_group, num_of_frames))\n",
+ "recv_process.start()\n",
+ "send_process.start()\n",
+ "print('Starting streaming (hef=\\'{}\\', num_of_frames={})'.format(model_name, num_of_frames))\n",
+ "with network_group.activate(network_group_params):\n",
+ " send_process.join()\n",
+ " recv_process.join()\n",
+ "print('Done')"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
--- /dev/null
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Python power measurement tutorial\n",
+ "\n",
+ "This tutorial will show how to perform a power measurement on the chip.\n",
+ "\n",
+ "The Hailo chip supports power measurement which is done via the control protocol.\n",
+ "\n",
+ "**Requirements:**\n",
+ "\n",
+ "* Run the notebook inside the Python virtual environment: ```source hailo_virtualenv/bin/activate```\n",
+ "\n",
+ "**Attention:**\n",
+ "\n",
+ "* These examples should run in a different process than the one that performs the actual inference.\n"
+ ]
+ },
+ {
+ "source": [
+ "## Single power measurement"
+ ],
+ "cell_type": "markdown",
+ "metadata": {}
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%matplotlib inline\n",
+ "import time\n",
+ "\n",
+ "from hailo_platform import PcieDevice, DvmTypes, PowerMeasurementTypes, SamplingPeriod, AveragingFactor, MeasurementBufferIndex # noqa F401\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Initialize the hardware object:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "target = PcieDevice()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "When using the ``power_measurement()`` function with no parameters, the function tries to detect which board is connected (evaluation board, M.2 or mPCIe) and determine the DVM accordingly (at the moment only the mentioned boards are supported). \n",
+ "\n",
+ "The parameter ``dvm`` (of type ``DvmTypes``) defines which DVM will be measured. The user can choose a specific DVM or choose the default DVM. The meaning of the default DVM changes according to the board or module in use. \n",
+ "\n",
+ "The default for the evaluation board is the sum of three DVMs: ``DvmTypes.VDD_CORE``, ``DvmTypes.MIPI_AVDD`` and ``DvmTypes.AVDD_H``. The sum of these three DVMs approximates of the total power consumption of the chip in PCIe setups. Only power can be measured using this default option, as voltage and current can't be summed up this way. \n",
+ "\n",
+ "The default for platforms supporting current monitoring, such as M.2 and mPCIe modules, is ``DvmTypes.OVERCURRENT_PROTECTION``, which measures the power consumption of the whole module. \n",
+ "\n",
+ "See the API documentation for further details about the supported DVMs and measurement types.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "single_power_measurement = target.control.power_measurement()\n",
+ "print('Power from single measurement: {} W'.format(single_power_measurement))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Periodic power measurement\n",
+ "\n",
+ "In the following example, a periodic power measurement is taken.\n",
+ "\n",
+ "A measurement index is selected. It is a member of the enum class MeasurementBufferIndex (between 0 and 3). The DVM is not given so the default DVM will be used, as explained above.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "buffer_index = MeasurementBufferIndex.MEASUREMENT_BUFFER_INDEX_0\n",
+ "target.control.set_power_measurement(buffer_index=buffer_index)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The following call to ``start_power_measurement()`` allows to configure the power sampling frequency. In this case we keep the default configuration. The API documentation provides more details. \n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "target.control.start_power_measurement()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Clear old samples and statistics (min, max, average) each time the measurement is taken from the chip."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "should_clear = True"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The power measurement is read every second, for 10 seconds.\n",
+ "\n",
+ "The firmware calculates the min, max, and average of all the values from the sensor. Note that the average calculated by the firmware is the \"average of averages\". This is the average of all values that have already been averaged by the sensor. The host then requests these values from the firmware every second by calling the ``get_power_measurement()`` function. The host can also read the average time interval between new sensor values."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "for _ in range(10):\n",
+ " time.sleep(1)\n",
+ " # Get saved power measurement values from the firmware.\n",
+ " measurements = target.control.get_power_measurement(buffer_index=buffer_index, should_clear=should_clear)\n",
+ " print('Average power is {} W. Min power is {} W. Max power is {} W.\\nAverage time between power samples is {} mS\\n'.format(measurements.average_value, measurements.min_value, measurements.max_value, measurements.average_time_value_milliseconds))\n",
+ " \n",
+ "# Stop performing periodic power measurement\n",
+ "target.control.stop_power_measurement()"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
\ No newline at end of file
netaddr==0.8.0
netifaces==0.10.9
numpy==1.19.4
-six==1.15.0
typing_extensions==4.1.1
verboselogs==1.7
virtualenv==20.4.3
import os
-import sys
+import json
from setuptools import setup, find_packages
from wheel.bdist_wheel import bdist_wheel as orig_bdist_wheel
self.root_is_pure = False
-def _get_pyhailort_lib():
+def _get_pyhailort_lib_path():
+ conf_file_path = os.path.join(os.path.abspath(os.path.dirname( __file__ )), "wheel_conf.json")
extension = {
"posix": "so",
"nt": "pyd", # Windows
}[os.name]
- py = "".join(map(str, sys.version_info[:2]))
+ if not os.path.isfile(conf_file_path):
+ return None
- return f"drivers/hailort/_pyhailort*{py}*.{extension}"
+ with open(conf_file_path, "r") as conf_file:
+ content = json.load(conf_file)
+ return f"../hailo_platform/pyhailort/_pyhailort*{content['py_version']}*{content['arch']}*.{extension}"
+
+def _get_package_paths():
+ packages = []
+ pyhailort_lib = _get_pyhailort_lib_path()
+ if pyhailort_lib:
+ packages.append(pyhailort_lib)
+ packages.append("../hailo_tutorials/notebooks/*")
+ packages.append("../hailo_tutorials/hefs/*")
+ return packages
if __name__ == "__main__":
description="HailoRT",
entry_points={
"console_scripts": [
- "hailo=hailo_platform.tools.cmd_utils.main:main",
+ "hailo=hailo_platform.tools.hailocli.main:main",
]
},
install_requires=[
"future",
"netaddr",
"netifaces",
- "six",
"verboselogs",
# Pinned versions
"numpy==1.19.4",
],
name="hailort",
package_data={
- "hailo_platform": [
- _get_pyhailort_lib(), # packs _pyhailort library for _pyhailort imports
- ],
+ "hailo_platform": _get_package_paths(),
},
packages=find_packages(),
platforms=[
"linux_aarch64",
],
url="https://hailo.ai/",
- version="4.6.0",
+ version="4.8.0",
zip_safe=False,
)
+++ /dev/null
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "\n",
- "# Python inference tutorial\n",
- "\n",
- "This tutorial will walk you through the inference process.\n",
- "\n",
- "**Requirements:**\n",
- "\n",
- "* Run the notebook inside the Python virtual environment: ```source hailo_virtualenv/bin/activate```"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Standalone hardware deployment\n",
- "\n",
- "The standalone flow allows direct access to the HW, developing applications directly on top of Hailo\n",
- "core HW, using HailoRT. This way we can use the Hailo hardware without Tensorflow, and\n",
- "even without the Hailo SDK (after the HEF is built).\n",
- "\n",
- "An HEF is Hailo’s binary format for neural networks. The HEF files contain:\n",
- "\n",
- "* Target HW configuration\n",
- "* Weights\n",
- "* Metadata for HailoRT (e.g. input/output scaling)\n",
- "\n",
- "First create the desired target object. In our example we use the Hailo-8 PCIe interface:\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "import numpy as np\n",
- "from multiprocessing import Process\n",
- "from hailo_platform import (HEF, PcieDevice, HailoStreamInterface, InferVStreams, ConfigureParams,\n",
- " InputVStreamParams, OutputVStreamParams, InputVStreams, OutputVStreams, FormatType)\n",
- "\n",
- "# The target can be used as a context manager (\"with\" statement) to ensure it's released on time.\n",
- "# Here it's avoided for the sake of simplicity\n",
- "target = PcieDevice()\n",
- "\n",
- "# Loading compiled HEFs to device:\n",
- "model_name = 'resnet_v1_18'\n",
- "hef_path = '../hefs/{}.hef'.format(model_name) \n",
- "hef = HEF(hef_path)\n",
- " \n",
- "# Configure network groups\n",
- "configure_params = ConfigureParams.create_from_hef(hef=hef, interface=HailoStreamInterface.PCIe)\n",
- "network_groups = target.configure(hef, configure_params)\n",
- "network_group = network_groups[0]\n",
- "network_group_params = network_group.create_params()\n",
- "\n",
- "# Create input and output virtual streams params\n",
- "# Quantized argument signifies whether or not the incoming data is already quantized.\n",
- "# Data is quantized by HailoRT if and only if quantized == False .\n",
- "input_vstreams_params = InputVStreamParams.make(network_group, quantized=False, format_type=FormatType.FLOAT32)\n",
- "output_vstreams_params = OutputVStreamParams.make(network_group, quantized=True, format_type=FormatType.UINT8)\n",
- "\n",
- "# Define dataset params\n",
- "input_vstream_info = hef.get_input_vstream_infos()[0]\n",
- "output_vstream_info = hef.get_output_vstream_infos()[0]\n",
- "image_height, image_width, channels = input_vstream_info.shape\n",
- "num_of_images = 10\n",
- "low, high = 2, 20\n",
- "\n",
- "# Generate random dataset\n",
- "dataset = np.random.randint(low, high, (num_of_images, image_height, image_width, channels)).astype(np.float32)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### Running hardware inference\n",
- "Infer the model and then display the output shape:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "# Infer \n",
- "with InferVStreams(network_group, input_vstreams_params, output_vstreams_params) as infer_pipeline:\n",
- " input_data = {input_vstream_info.name: dataset}\n",
- " with network_group.activate(network_group_params):\n",
- " infer_results = infer_pipeline.infer(input_data)\n",
- " print('Stream output shape is {}'.format(infer_results[output_vstream_info.name].shape))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Streaming inference\n",
- "\n",
- "This section shows how to run streaming inference using multiple processes in Python.\n",
- "\n",
- "We will not use infer. Instead we will use a send and receive model.\n",
- "The send function and the receive function will run in different processes."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Define the send and receive functions:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "def send(configured_network, num_frames):\n",
- " vstreams_params = InputVStreamParams.make(configured_network)\n",
- " configured_network.wait_for_activation(1000)\n",
- " with InputVStreams(configured_network, vstreams_params) as vstreams:\n",
- " vstream_to_buffer = {vstream: np.ndarray([1] + list(vstream.shape), dtype=vstream.dtype) for vstream in vstreams}\n",
- " for _ in range(num_frames):\n",
- " for vstream, buff in vstream_to_buffer.items():\n",
- " vstream.send(buff)\n",
- "\n",
- "def recv(configured_network, vstreams_params, num_frames):\n",
- " configured_network.wait_for_activation(1000)\n",
- " with OutputVStreams(configured_network, vstreams_params) as vstreams:\n",
- " for _ in range(num_frames):\n",
- " for vstream in vstreams:\n",
- " data = vstream.recv()\n",
- "\n",
- "def recv_all(configured_network, num_frames):\n",
- " vstreams_params_groups = OutputVStreamParams.make_groups(configured_network)\n",
- " recv_procs = []\n",
- " for vstreams_params in vstreams_params_groups:\n",
- " proc = Process(target=recv, args=(configured_network, vstreams_params, num_frames))\n",
- " proc.start()\n",
- " recv_procs.append(proc)\n",
- " for proc in recv_procs:\n",
- " proc.join()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Define the amount of frames to stream, define the processes, create the target and run processes:\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "# Define the amount of frames to stream\n",
- "num_of_frames = 1000\n",
- "\n",
- "send_process = Process(target=send, args=(network_group, num_of_frames))\n",
- "recv_process = Process(target=recv_all, args=(network_group, num_of_frames))\n",
- "recv_process.start()\n",
- "send_process.start()\n",
- "print('Starting streaming (hef=\\'{}\\', num_of_frames={})'.format(model_name, num_of_frames))\n",
- "with network_group.activate(network_group_params):\n",
- " send_process.join()\n",
- " recv_process.join()\n",
- "print('Done')"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.6.9"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
+++ /dev/null
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Python power measurement tutorial\n",
- "\n",
- "This tutorial will show how to perform a power measurement on the chip.\n",
- "\n",
- "The Hailo chip supports power measurement which is done via the control protocol.\n",
- "\n",
- "**Requirements:**\n",
- "\n",
- "* Run the notebook inside the Python virtual environment: ```source hailo_virtualenv/bin/activate```\n",
- "\n",
- "**Attention:**\n",
- "\n",
- "* These examples should run in a different process than the one that performs the actual inference.\n"
- ]
- },
- {
- "source": [
- "## Single power measurement"
- ],
- "cell_type": "markdown",
- "metadata": {}
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "%matplotlib inline\n",
- "import time\n",
- "\n",
- "from hailo_platform.drivers.hailo_controller.power_measurement import DvmTypes, PowerMeasurementTypes, SamplingPeriod, AveragingFactor # noqa F401\n",
- "from hailo_platform import PcieDevice"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Initialize the hardware object:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "target = PcieDevice()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "When using the ``power_measurement()`` function with no parameters, the function tries to detect which board is connected (evaluation board, M.2 or mPCIe) and determine the DVM accordingly (at the moment only the mentioned boards are supported). \n",
- "\n",
- "The parameter ``dvm`` (of type ``DvmTypes``) defines which DVM will be measured. The user can choose a specific DVM or choose the default DVM. The meaning of the default DVM changes according to the board or module in use. \n",
- "\n",
- "The default for the evaluation board is the sum of three DVMs: ``DvmTypes.VDD_CORE``, ``DvmTypes.MIPI_AVDD`` and ``DvmTypes.AVDD_H``. The sum of these three DVMs approximates of the total power consumption of the chip in PCIe setups. Only power can be measured using this default option, as voltage and current can't be summed up this way. \n",
- "\n",
- "The default for platforms supporting current monitoring, such as M.2 and mPCIe modules, is ``DvmTypes.OVERCURRENT_PROTECTION``, which measures the power consumption of the whole module. \n",
- "\n",
- "See the API documentation for further details about the supported DVMs and measurement types.\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "single_power_measurement = target.control.power_measurement()\n",
- "print('Power from single measurement: {} W'.format(single_power_measurement))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Periodic power measurement\n",
- "\n",
- "In the following example, a periodic power measurement is taken.\n",
- "\n",
- "A measurement index is selected. It is a number between 0 and 3. The DVM is not given so the default DVM will be used, as explained above.\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "index = 0\n",
- "target.control.set_power_measurement(index)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The following call to ``start_power_measurement()`` allows to configure the power sampling frequency. In this case we keep the default configuration. The API documentation provides more details. \n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "target.control.start_power_measurement()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Clear old samples and statistics (min, max, average) each time the measurement is taken from the chip."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "should_clear = True"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The power measurement is read every second, for 10 seconds.\n",
- "\n",
- "The firmware calculates the min, max, and average of all the values from the sensor. Note that the average calculated by the firmware is the \"average of averages\". This is the average of all values that have already been averaged by the sensor. The host then requests these values from the firmware every second by calling the ``get_power_measurement()`` function. The host can also read the average time interval between new sensor values."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "for _ in range(10):\n",
- " time.sleep(1)\n",
- " # Get saved power measurement values from the firmware.\n",
- " measurements = target.control.get_power_measurement(index, should_clear=should_clear)\n",
- " print('Average power is {} W. Min power is {} W. Max power is {} W.\\nAverage time between power samples is {} mS\\n'.format(measurements.average_value, measurements.min_value, measurements.max_value, measurements.average_time_value_milliseconds))\n",
- " \n",
- "# Stop performing periodic power measurement\n",
- "target.control.stop_power_measurement()"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.6.9"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
\ No newline at end of file
cmake_minimum_required(VERSION 3.0.0)
+option(HAILO_BUILD_PYHAILORT_INTERNAL OFF)
+
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
string(REPLACE "." "" dpython ${PYBIND11_PYTHON_VERSION}) # E.g "3.5" -> "35"
if(${dpython} LESS "38")
endif()
set(PYHAILORT_DIR ${CMAKE_CURRENT_LIST_DIR})
-add_subdirectory(internal)
+
pybind11_add_module(_pyhailort
pyhailort.cpp
+ device_api.cpp
+ hef_api.cpp
+ vstream_api.cpp
${HAILORT_COMMON_CPP_SOURCES}
)
+
+set_target_properties(_pyhailort PROPERTIES
+ CXX_STANDARD 14
+ CXX_STANDARD_REQUIRED YES
+)
+
target_include_directories(_pyhailort
PRIVATE
$<BUILD_INTERFACE:${HAILORT_INC_DIR}>
endif()
target_compile_options(_pyhailort PRIVATE ${HAILORT_COMPILE_OPTIONS})
exclude_archive_libs_symbols(_pyhailort)
+
+if (HAILO_BUILD_PYHAILORT_INTERNAL)
+ add_subdirectory(internal)
+ # copy files to venv
+ if(HAILO_BUILD_PYHAILORT_VENV)
+ add_custom_target(pyhailort_internal_venv ALL
+ COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:_pyhailort_internal> ${PROJECT_SOURCE_DIR}/platform_internals/hailo_platform_internals/pyhailort/
+ )
+ add_dependencies(pyhailort_internal_venv _pyhailort_internal)
+ endif()
+endif()
namespace hailort
{
-
-int convert_format_type_to_int(const hailo_format_type_t& type)
+class HailoRTBindingsCommon
{
- switch (type) {
- case HAILO_FORMAT_TYPE_UINT8:
- return 1;
- case HAILO_FORMAT_TYPE_UINT16:
- return 2;
- case HAILO_FORMAT_TYPE_FLOAT32:
- return 4;
- default:
- throw HailoRTStatusException("Invalid format type.");
+public:
+ static std::string convert_format_type_to_string(const hailo_format_type_t &type)
+ {
+ switch (type) {
+ case HAILO_FORMAT_TYPE_UINT8:
+ return "uint8";
+ case HAILO_FORMAT_TYPE_UINT16:
+ return "uint16";
+ case HAILO_FORMAT_TYPE_FLOAT32:
+ return "float32";
+ default:
+ throw HailoRTStatusException("Invalid format type.");
+ }
}
-}
-std::string convert_format_type_to_string(const hailo_format_type_t& type)
-{
- switch (type) {
- case HAILO_FORMAT_TYPE_UINT8:
- return "uint8";
- case HAILO_FORMAT_TYPE_UINT16:
- return "uint16";
- case HAILO_FORMAT_TYPE_FLOAT32:
- return "float32";
- default:
- throw HailoRTStatusException("Invalid format type.");
+ static std::vector<size_t> get_pybind_shape(const hailo_vstream_info_t& vstream_info, const hailo_format_t &user_format)
+ {
+ // We are using user_format instead of hw format inside the vstream_info
+ const auto shape = vstream_info.shape;
+ // TODO: support no transformations (i.e. use stream_info.hw_shape) (SDK-16811)
+ switch (user_format.order)
+ {
+ case HAILO_FORMAT_ORDER_HAILO_NMS:
+ return { HailoRTCommon::get_nms_host_shape_size(vstream_info.nms_shape) };
+ case HAILO_FORMAT_ORDER_NC:
+ return {shape.features};
+ case HAILO_FORMAT_ORDER_NHW:
+ return {shape.height, shape.width};
+ default:
+ return {shape.height, shape.width, shape.features};
+ }
}
-}
-std::vector<size_t> get_pybind_shape(const hailo_vstream_info_t& vstream_info, const hailo_format_t &user_format)
-{
- // We are using user_format instead of hw format inside the vstream_info
- const auto shape = vstream_info.shape;
- // TODO: support no transformations (i.e. use stream_info.hw_shape) (SDK-16811)
- switch (user_format.order)
+ static py::dtype get_dtype(const hailo_format_type_t &type)
{
- case HAILO_FORMAT_ORDER_HAILO_NMS:
- return { HailoRTCommon::get_nms_host_shape_size(vstream_info.nms_shape) };
- case HAILO_FORMAT_ORDER_NC:
- return {shape.features};
- case HAILO_FORMAT_ORDER_NHW:
- return {shape.height, shape.width};
- default:
- return {shape.height, shape.width, shape.features};
+ return py::dtype(HailoRTBindingsCommon::convert_format_type_to_string(type));
}
-}
+};
} /* namespace hailort */
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file device_api.cpp
+ * @brief implementations of binding to hailo device
+ *
+ **/
+
+#include "device_api.hpp"
+
+
+namespace hailort
+{
+
+DeviceWrapper DeviceWrapper::create_pcie(hailo_pcie_device_info_t &device_info)
+{
+ auto device = Device::create_pcie(device_info);
+ VALIDATE_EXPECTED(device);
+
+ return DeviceWrapper(device.release());
+}
+
+DeviceWrapper DeviceWrapper::create_eth(std::string &device_address, uint16_t port,
+ uint32_t timeout_milliseconds, uint8_t max_number_of_attempts)
+{
+ hailo_eth_device_info_t device_info = {};
+
+ /* Validate address length */
+ if (INET_ADDRSTRLEN < device_address.size()) {
+ EXIT_WITH_ERROR("device_address is too long")
+ }
+
+ device_info.host_address.sin_family = AF_INET;
+ device_info.host_address.sin_port = HAILO_ETH_PORT_ANY;
+ auto status = Socket::pton(AF_INET, HAILO_ETH_ADDRESS_ANY, &(device_info.host_address.sin_addr));
+ VALIDATE_STATUS(status);
+
+ device_info.device_address.sin_family = AF_INET;
+ device_info.device_address.sin_port = port;
+ status = Socket::pton(AF_INET, device_address.c_str(), &(device_info.device_address.sin_addr));
+ VALIDATE_STATUS(status);
+
+ device_info.timeout_millis = timeout_milliseconds;
+ device_info.max_number_of_attempts = max_number_of_attempts;
+ device_info.max_payload_size = HAILO_DEFAULT_ETH_MAX_PAYLOAD_SIZE;
+
+ auto device = Device::create_eth(device_info);
+ VALIDATE_EXPECTED(device);
+
+ return DeviceWrapper(device.release());
+}
+
+DeviceWrapper DeviceWrapper::create_core()
+{
+ auto device = Device::create_core_device();
+ VALIDATE_EXPECTED(device);
+
+ return DeviceWrapper(device.release());
+}
+
+void DeviceWrapper::release()
+{
+ m_device.reset();
+}
+
+/* Controls */
+hailo_device_identity_t DeviceWrapper::identify()
+{
+ auto board_info = device().identify();
+ VALIDATE_EXPECTED(board_info);
+
+ return board_info.release();
+}
+
+hailo_core_information_t DeviceWrapper::core_identify()
+{
+ auto core_info = device().core_identify();
+ VALIDATE_EXPECTED(core_info);
+
+ return core_info.release();
+}
+
+void DeviceWrapper::set_fw_logger(hailo_fw_logger_level_t level, uint32_t interface_mask)
+{
+ auto status = device().set_fw_logger(level, interface_mask);
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::set_throttling_state(bool should_activate)
+{
+ auto status = device().set_throttling_state(should_activate);
+ VALIDATE_STATUS(status);
+}
+
+bool DeviceWrapper::get_throttling_state()
+{
+
+ auto is_active_expected = device().get_throttling_state();
+ VALIDATE_EXPECTED(is_active_expected);
+
+ return is_active_expected.release();
+}
+
+void DeviceWrapper::set_overcurrent_state(bool should_activate)
+{
+ auto status = device().set_overcurrent_state(should_activate);
+ VALIDATE_STATUS(status);
+}
+
+bool DeviceWrapper::get_overcurrent_state()
+{
+ auto is_required_expected = device().get_overcurrent_state();
+ VALIDATE_EXPECTED(is_required_expected);
+
+ return is_required_expected.release();
+}
+
+py::bytes DeviceWrapper::read_memory(uint32_t address, uint32_t length)
+{
+ std::unique_ptr<std::string> response = make_unique_nothrow<std::string>(length, '\x00');
+ VALIDATE_NOT_NULL(response);
+
+ MemoryView data_view(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(response->data())), length);
+ auto status = device().read_memory(address, data_view);
+ VALIDATE_STATUS(status);
+
+ return *response;
+}
+
+void DeviceWrapper::write_memory(uint32_t address, py::bytes data, uint32_t length)
+{
+ auto status = device().write_memory(address, MemoryView(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(std::string(data).c_str())), length));
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::test_chip_memories()
+{
+ hailo_status status = device().test_chip_memories();
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::i2c_write(hailo_i2c_slave_config_t *slave_config, uint32_t register_address, py::bytes data,
+ uint32_t length)
+{
+ VALIDATE_NOT_NULL(slave_config);
+
+ std::string data_str(data);
+ MemoryView data_view = MemoryView::create_const(data_str.c_str(), length);
+ auto status = device().i2c_write(*slave_config, register_address, data_view);
+ VALIDATE_STATUS(status);
+}
+
+py::bytes DeviceWrapper::i2c_read(hailo_i2c_slave_config_t *slave_config, uint32_t register_address, uint32_t length)
+{
+ VALIDATE_NOT_NULL(slave_config);
+
+ std::unique_ptr<std::string> response = make_unique_nothrow<std::string>(length, '\x00');
+ VALIDATE_NOT_NULL(response);
+
+ MemoryView data_view(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(response->data())), length);
+ auto status = device().i2c_read(*slave_config, register_address, data_view);
+ VALIDATE_STATUS(status);
+
+ return *response;
+}
+
+float32_t DeviceWrapper::power_measurement(hailo_dvm_options_t dvm,
+ hailo_power_measurement_types_t measurement_type)
+{
+ auto measurement = device().power_measurement(dvm, measurement_type);
+ VALIDATE_EXPECTED(measurement);
+
+ return measurement.release();
+}
+
+void DeviceWrapper::start_power_measurement(hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period)
+{
+ auto status = device().start_power_measurement(averaging_factor, sampling_period);
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::set_power_measurement(hailo_measurement_buffer_index_t buffer_index, hailo_dvm_options_t dvm,
+ hailo_power_measurement_types_t measurement_type)
+{
+ auto status = device().set_power_measurement(buffer_index,
+ dvm, measurement_type);
+ VALIDATE_STATUS(status);
+}
+
+PowerMeasurementData DeviceWrapper::get_power_measurement(hailo_measurement_buffer_index_t buffer_index, bool should_clear)
+{
+ auto measurement_data = device().get_power_measurement(buffer_index,
+ should_clear);
+ VALIDATE_EXPECTED(measurement_data);
+
+ return PowerMeasurementData(measurement_data.release());
+}
+
+void DeviceWrapper::stop_power_measurement()
+{
+ auto status = device().stop_power_measurement();
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::reset(hailo_reset_device_mode_t mode)
+{
+ auto status = device().reset(mode);
+ VALIDATE_STATUS(status);
+}
+
+hailo_fw_user_config_information_t DeviceWrapper::examine_user_config()
+{
+ auto user_config_info = device().examine_user_config();
+ VALIDATE_EXPECTED(user_config_info);
+
+ return user_config_info.release();
+}
+
+py::bytes DeviceWrapper::read_user_config()
+{
+ auto config_buffer = device().read_user_config();
+ VALIDATE_EXPECTED(config_buffer);
+
+ std::unique_ptr<std::string> response = make_unique_nothrow<std::string>(
+ const_cast<char*>(reinterpret_cast<const char*>(config_buffer->data())), config_buffer->size());
+ VALIDATE_NOT_NULL(response);
+
+ return *response;
+}
+
+void DeviceWrapper::write_user_config(py::bytes data)
+{
+ std::string data_str(data);
+ MemoryView data_view = MemoryView::create_const(data_str.c_str(), data_str.size());
+ auto status = device().write_user_config(data_view);
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::erase_user_config()
+{
+ auto status = device().erase_user_config();
+ VALIDATE_STATUS(status);
+}
+
+py::bytes DeviceWrapper::read_board_config()
+{
+ auto config_buffer = device().read_board_config();
+ VALIDATE_EXPECTED(config_buffer);
+
+ std::unique_ptr<std::string> response = make_unique_nothrow<std::string>(
+ const_cast<char*>(reinterpret_cast<const char*>(config_buffer->data())), config_buffer->size());
+ VALIDATE_NOT_NULL(response);
+
+ return *response;
+}
+
+void DeviceWrapper::write_board_config(py::bytes data)
+{
+ std::string data_str(data);
+ MemoryView data_view = MemoryView::create_const(data_str.c_str(), data_str.size());
+ auto status = device().write_board_config(data_view);
+ VALIDATE_STATUS(status);
+}
+
+hailo_extended_device_information_t DeviceWrapper::get_extended_device_information()
+{
+ auto extended_device_info = device().get_extended_device_information();
+ VALIDATE_EXPECTED(extended_device_info);
+
+ return extended_device_info.release();
+}
+
+hailo_health_info_t DeviceWrapper::get_health_information()
+{
+ auto health_info = device().get_health_information();
+ VALIDATE_EXPECTED(health_info);
+
+ return health_info.release();
+}
+
+void DeviceWrapper::sensor_store_config(uint32_t section_index, uint32_t reset_data_size, uint32_t sensor_type, const std::string &config_file_path,
+ uint16_t config_height, uint16_t config_width, uint16_t config_fps, const std::string &config_name)
+{
+ auto status = device().store_sensor_config(section_index, static_cast<hailo_sensor_types_t>(sensor_type), reset_data_size,
+ config_height, config_width, config_fps, config_file_path, config_name);
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::store_isp_config(uint32_t reset_config_size, uint16_t config_height, uint16_t config_width, uint16_t config_fps,
+ const std::string &isp_static_config_file_path, const std::string &isp_runtime_config_file_path, const std::string &config_name)
+{
+ auto status = device().store_isp_config(reset_config_size, config_height, config_width, config_fps,
+ isp_static_config_file_path, isp_runtime_config_file_path, config_name);
+ VALIDATE_STATUS(status);
+}
+
+py::bytes DeviceWrapper::sensor_get_sections_info()
+{
+ auto buffer = device().sensor_get_sections_info();
+ VALIDATE_EXPECTED(buffer);
+
+ std::unique_ptr<std::string> response = make_unique_nothrow<std::string>(
+ const_cast<char*>(reinterpret_cast<const char*>(buffer->data())), buffer->size());
+ VALIDATE_NOT_NULL(response);
+
+ return *response;
+}
+
+void DeviceWrapper::sensor_set_i2c_bus_index(uint32_t sensor_type, uint32_t bus_index)
+{
+ hailo_status status = device().sensor_set_i2c_bus_index(static_cast<hailo_sensor_types_t>(sensor_type), bus_index);
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::sensor_load_and_start_config(uint32_t section_index)
+{
+ auto status = device().sensor_load_and_start_config(section_index);
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::sensor_reset(uint32_t section_index)
+{
+ auto status = device().sensor_reset(section_index);
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::sensor_set_generic_i2c_slave(uint16_t slave_address,
+ uint8_t register_address_size, uint8_t bus_index, uint8_t should_hold_bus, uint8_t endianness)
+{
+ auto status = device().sensor_set_generic_i2c_slave(slave_address, register_address_size,
+ bus_index, should_hold_bus, endianness);
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::firmware_update(py::bytes fw_bin, uint32_t fw_bin_length, bool should_reset)
+{
+ auto status = device().firmware_update(MemoryView::create_const(std::string(fw_bin).c_str(), fw_bin_length),
+ should_reset);
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::second_stage_update(py::bytes second_stage_bin, uint32_t second_stage_bin_length)
+{
+ auto status = device().second_stage_update((uint8_t *)std::string(second_stage_bin).c_str(),
+ second_stage_bin_length);
+ VALIDATE_STATUS(status);
+}
+
+py::list DeviceWrapper::configure(const HefWrapper &hef,
+ const NetworkGroupsParamsMap &configure_params)
+{
+ auto network_groups = device().configure(*hef.hef_ptr(), configure_params);
+ VALIDATE_EXPECTED(network_groups);
+
+ py::list results;
+ for (const auto &network_group : network_groups.value()) {
+ results.append(network_group.get());
+ }
+
+ return results;
+}
+
+void DeviceWrapper::set_pause_frames(bool rx_pause_frames_enable)
+{
+ auto status = device().set_pause_frames(rx_pause_frames_enable);
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::wd_enable(hailo_cpu_id_t cpu_id)
+{
+ hailo_status status = device().wd_enable(cpu_id);
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::wd_disable(hailo_cpu_id_t cpu_id)
+{
+ hailo_status status = device().wd_disable(cpu_id);
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::wd_config(hailo_cpu_id_t cpu_id, uint32_t wd_cycles, hailo_watchdog_mode_t wd_mode)
+{
+ auto status = device().wd_config(cpu_id, wd_cycles, wd_mode);
+ VALIDATE_STATUS(status);
+}
+
+uint32_t DeviceWrapper::previous_system_state(hailo_cpu_id_t cpu_id)
+{
+ auto system_state = device().previous_system_state(cpu_id);
+ VALIDATE_EXPECTED(system_state);
+
+ return system_state.release();
+}
+
+hailo_chip_temperature_info_t DeviceWrapper::get_chip_temperature()
+{
+ auto temp_info = device().get_chip_temperature();
+ VALIDATE_EXPECTED(temp_info);
+
+ return temp_info.release();
+}
+
+void DeviceWrapper::set_notification_callback(const std::function<void(uintptr_t, const hailo_notification_t&, py::object)> &callback,
+ hailo_notification_id_t notification_id, py::object opaque)
+{
+ // we capture opaque and move it because when opaque goes out of score it will be deleted,
+ // so capturing it ensures that it will not be deleted
+ hailo_status status = device().set_notification_callback(
+ [callback, op = std::move(opaque)] (Device &device, const hailo_notification_t ¬ification, void* opaque) {
+ (void)opaque;
+ callback((uintptr_t)(&device), notification, op);
+ }, notification_id, nullptr);
+ VALIDATE_STATUS(status);
+}
+
+void DeviceWrapper::remove_notification_callback(hailo_notification_id_t notification_id)
+{
+ auto status = device().remove_notification_callback(notification_id);
+ VALIDATE_STATUS(status);
+}
+
+py::bytes DeviceWrapper::read_log(size_t byte_count, hailo_cpu_id_t cpu_id)
+{
+ std::string response;
+
+ response.reserve(byte_count);
+ response.resize(byte_count);
+
+ MemoryView response_view ((&response[0]), byte_count);
+ auto response_size_expected = device().read_log(response_view, cpu_id);
+ VALIDATE_EXPECTED(response_size_expected);
+
+ response.resize(response_size_expected.release());
+ return py::bytes(response);
+}
+
+void DeviceWrapper::direct_write_memory(uint32_t address, py::bytes buffer)
+{
+ const auto buffer_str = static_cast<std::string>(buffer);
+ hailo_status status = device().direct_write_memory(address, buffer_str.c_str(),
+ (uint32_t) (buffer_str.length()));
+ VALIDATE_STATUS(status);
+}
+
+py::bytes DeviceWrapper::direct_read_memory(uint32_t address, uint32_t size)
+{
+ std::string buffer_str;
+
+ buffer_str.reserve(size);
+ buffer_str.resize(size);
+
+ hailo_status status = device().direct_read_memory(address, (char*)buffer_str.c_str(), size);
+ VALIDATE_STATUS(status);
+
+ buffer_str.resize(size);
+ return py::bytes(buffer_str);
+}
+
+void DeviceWrapper::add_to_python_module(py::module &m)
+{
+ py::class_<DeviceWrapper>(m, "Device")
+ // C'tors
+ .def("create_pcie", &DeviceWrapper::create_pcie)
+ .def("create_eth", &DeviceWrapper::create_eth)
+ .def("create_core", &DeviceWrapper::create_core)
+ .def("release", &DeviceWrapper::release)
+
+ //HEF
+ .def("configure", &DeviceWrapper::configure)
+
+ // Controls
+ .def("identify", &DeviceWrapper::identify)
+ .def("core_identify", &DeviceWrapper::core_identify)
+ .def("set_fw_logger", &DeviceWrapper::set_fw_logger)
+ .def("read_memory", &DeviceWrapper::read_memory)
+ .def("write_memory", &DeviceWrapper::write_memory)
+ .def("power_measurement", &DeviceWrapper::power_measurement)
+ .def("start_power_measurement", &DeviceWrapper::start_power_measurement)
+ .def("stop_power_measurement", &DeviceWrapper::stop_power_measurement)
+ .def("set_power_measurement", &DeviceWrapper::set_power_measurement)
+ .def("get_power_measurement", &DeviceWrapper::get_power_measurement)
+ .def("firmware_update", &DeviceWrapper::firmware_update)
+ .def("second_stage_update", &DeviceWrapper::second_stage_update)
+ .def("examine_user_config", &DeviceWrapper::examine_user_config)
+ .def("read_user_config", &DeviceWrapper::read_user_config)
+ .def("write_user_config", &DeviceWrapper::write_user_config)
+ .def("erase_user_config", &DeviceWrapper::erase_user_config)
+ .def("read_board_config", &DeviceWrapper::read_board_config)
+ .def("write_board_config", &DeviceWrapper::write_board_config)
+ .def("i2c_write", &DeviceWrapper::i2c_write)
+ .def("i2c_read", &DeviceWrapper::i2c_read)
+ .def("sensor_store_config", &DeviceWrapper::sensor_store_config)
+ .def("store_isp_config", &DeviceWrapper::store_isp_config)
+ .def("sensor_set_i2c_bus_index", &DeviceWrapper::sensor_set_i2c_bus_index)
+ .def("sensor_load_and_start_config", &DeviceWrapper::sensor_load_and_start_config)
+ .def("sensor_reset", &DeviceWrapper::sensor_reset)
+ .def("sensor_set_generic_i2c_slave", &DeviceWrapper::sensor_set_generic_i2c_slave)
+ .def("sensor_get_sections_info", &DeviceWrapper::sensor_get_sections_info)
+ .def("reset", &DeviceWrapper::reset)
+ .def("wd_enable", &DeviceWrapper::wd_enable)
+ .def("wd_disable", &DeviceWrapper::wd_disable)
+ .def("wd_config", &DeviceWrapper::wd_config)
+ .def("previous_system_state", &DeviceWrapper::previous_system_state)
+ .def("get_chip_temperature", &DeviceWrapper::get_chip_temperature)
+ .def("get_extended_device_information", &DeviceWrapper::get_extended_device_information)
+ .def("set_pause_frames", &DeviceWrapper::set_pause_frames)
+ .def("test_chip_memories", &DeviceWrapper::test_chip_memories)
+ .def("_get_health_information", &DeviceWrapper::get_health_information)
+ .def("set_throttling_state", &DeviceWrapper::set_throttling_state)
+ .def("get_throttling_state", &DeviceWrapper::get_throttling_state)
+ .def("_set_overcurrent_state", &DeviceWrapper::set_overcurrent_state)
+ .def("_get_overcurrent_state", &DeviceWrapper::get_overcurrent_state)
+ .def("direct_write_memory", &DeviceWrapper::direct_write_memory)
+ .def("direct_read_memory", &DeviceWrapper::direct_read_memory)
+ .def("read_log", &DeviceWrapper::read_log, py::return_value_policy::move)
+
+ .def("set_notification_callback", &DeviceWrapper::set_notification_callback)
+ .def("remove_notification_callback", &DeviceWrapper::remove_notification_callback)
+ ;
+}
+
+PowerMeasurementData::PowerMeasurementData(hailo_power_measurement_data_t &&c_power_data)
+{
+ m_average_value = c_power_data.average_value;
+ m_average_time_value_milliseconds = c_power_data.average_time_value_milliseconds;
+ m_min_value = c_power_data.min_value;
+ m_max_value = c_power_data.max_value;
+ m_total_number_of_samples = c_power_data.total_number_of_samples;
+}
+
+/* Return a tuple that fully encodes the state of the object */
+py::tuple PowerMeasurementData::get_state(const PowerMeasurementData &power_measurement_data)
+{
+ return py::make_tuple(
+ power_measurement_data.m_average_value,
+ power_measurement_data.m_average_time_value_milliseconds,
+ power_measurement_data.m_min_value,
+ power_measurement_data.m_max_value,
+ power_measurement_data.m_total_number_of_samples);
+}
+
+PowerMeasurementData PowerMeasurementData::set_state(py::tuple t)
+{
+ if (PowerMeasurementData::NUM_OF_MEMBERS != t.size())
+ throw std::runtime_error("Invalid power measurement data state!");
+
+ /* Create a new C++ instance */
+ hailo_power_measurement_data_t data;
+ data.average_value = t[0].cast<float32_t>();
+ data.average_time_value_milliseconds = t[1].cast<float32_t>();
+ data.min_value = t[2].cast<float32_t>();
+ data.max_value = t[3].cast<float32_t>();
+ data.total_number_of_samples = t[4].cast<uint32_t>();
+ return PowerMeasurementData(std::move(data));
+}
+
+bool PowerMeasurementData::equals(const PowerMeasurementData &other)
+{
+ return ((this->m_average_value == other.m_average_value) &&
+ (this->m_average_time_value_milliseconds == other.m_average_time_value_milliseconds) &&
+ (this->m_min_value == other.m_min_value) &&
+ (this->m_max_value == other.m_max_value) &&
+ (this->m_total_number_of_samples == other.m_total_number_of_samples));
+}
+
+} /* namespace hailort */
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file device_api.hpp
+ * @brief Defines binding to hailo device
+ *
+ **/
+
+#ifndef _DEVICE_API_HPP_
+#define _DEVICE_API_HPP_
+
+#include "utils.hpp"
+#include "hailo/hailort.hpp"
+#include "common/socket.hpp"
+#include "hef_api.hpp"
+
+#include <pybind11/pybind11.h>
+#include <pybind11/pybind11.h>
+
+
+namespace hailort
+{
+
+
+class PowerMeasurementData
+{
+public:
+ float32_t m_average_value;
+ float32_t m_average_time_value_milliseconds;
+ float32_t m_min_value;
+ float32_t m_max_value;
+ uint32_t m_total_number_of_samples;
+ PowerMeasurementData(hailo_power_measurement_data_t &&c_power_data);
+ bool equals(const PowerMeasurementData &other);
+ static py::tuple get_state(const PowerMeasurementData &power_measurement_data);
+ static PowerMeasurementData set_state(py::tuple t);
+ const static uint32_t NUM_OF_MEMBERS = 5;
+};
+
+
+class DeviceWrapper final
+{
+public:
+
+ static DeviceWrapper create_pcie(hailo_pcie_device_info_t &device_info);
+ static DeviceWrapper create_eth(std::string &device_address, uint16_t port,
+ uint32_t timeout_milliseconds, uint8_t max_number_of_attempts);
+ static DeviceWrapper create_core();
+ void release();
+
+ Device& device()
+ {
+ VALIDATE_NOT_NULL(m_device);
+ return *(m_device.get());
+ }
+
+ Device& operator*() // Used for control_internals
+ {
+ return device();
+ }
+
+ /* Controls */
+ hailo_device_identity_t identify();
+ hailo_core_information_t core_identify();
+ void set_fw_logger(hailo_fw_logger_level_t level, uint32_t interface_mask);
+ void set_throttling_state(bool should_activate);
+ bool get_throttling_state();
+ void set_overcurrent_state(bool should_activate);
+ bool get_overcurrent_state();
+ py::bytes read_memory(uint32_t address, uint32_t length);
+ void write_memory(uint32_t address, py::bytes data, uint32_t length);
+ void test_chip_memories();
+ void i2c_write(hailo_i2c_slave_config_t *slave_config, uint32_t register_address, py::bytes data,
+ uint32_t length);
+ py::bytes i2c_read(hailo_i2c_slave_config_t *slave_config, uint32_t register_address, uint32_t length);
+ float32_t power_measurement(hailo_dvm_options_t dvm,
+ hailo_power_measurement_types_t measurement_type);
+ void start_power_measurement(hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period);
+ void set_power_measurement(hailo_measurement_buffer_index_t buffer_index, hailo_dvm_options_t dvm,
+ hailo_power_measurement_types_t measurement_type);
+ PowerMeasurementData get_power_measurement(hailo_measurement_buffer_index_t buffer_index, bool should_clear);
+ void stop_power_measurement();
+ void reset(hailo_reset_device_mode_t mode);
+ hailo_fw_user_config_information_t examine_user_config();
+ py::bytes read_user_config();
+ void write_user_config(py::bytes data);
+ void erase_user_config();
+ py::bytes read_board_config();
+ void write_board_config(py::bytes data);
+ hailo_extended_device_information_t get_extended_device_information();
+ hailo_health_info_t get_health_information();
+ void sensor_store_config(uint32_t section_index, uint32_t reset_data_size, uint32_t sensor_type,
+ const std::string &config_file_path, uint16_t config_height, uint16_t config_width, uint16_t config_fps, const std::string &config_name);
+ void store_isp_config(uint32_t reset_config_size, uint16_t config_height, uint16_t config_width, uint16_t config_fps,
+ const std::string &isp_static_config_file_path, const std::string &isp_runtime_config_file_path, const std::string &config_name);
+ py::bytes sensor_get_sections_info();
+ void sensor_set_i2c_bus_index(uint32_t sensor_type, uint32_t bus_index);
+ void sensor_load_and_start_config(uint32_t section_index);
+ void sensor_reset(uint32_t section_index);
+ void sensor_set_generic_i2c_slave(uint16_t slave_address,
+ uint8_t register_address_size, uint8_t bus_index, uint8_t should_hold_bus, uint8_t endianness);
+ void firmware_update(py::bytes fw_bin, uint32_t fw_bin_length, bool should_reset);
+ void second_stage_update(py::bytes second_stage_bin, uint32_t second_stage_bin_length);
+ py::list configure(const HefWrapper &hef,
+ const NetworkGroupsParamsMap &configure_params={});
+ void set_pause_frames(bool rx_pause_frames_enable);
+ void wd_enable(hailo_cpu_id_t cpu_id);
+ void wd_disable(hailo_cpu_id_t cpu_id);
+ void wd_config(hailo_cpu_id_t cpu_id, uint32_t wd_cycles, hailo_watchdog_mode_t wd_mode);
+ uint32_t previous_system_state(hailo_cpu_id_t cpu_id);
+ hailo_chip_temperature_info_t get_chip_temperature();
+ void set_notification_callback(const std::function<void(uintptr_t, const hailo_notification_t&, py::object)> &callback,
+ hailo_notification_id_t notification_id, py::object opaque);
+ void remove_notification_callback(hailo_notification_id_t notification_id);
+ py::bytes read_log(size_t byte_count, hailo_cpu_id_t cpu_id);
+ void direct_write_memory(uint32_t address, py::bytes buffer);
+ py::bytes direct_read_memory(uint32_t address, uint32_t size);
+
+ static void add_to_python_module(py::module &m);
+
+private:
+ DeviceWrapper(std::unique_ptr<Device> &&device)
+ : m_device(std::move(device)) {}
+
+ std::unique_ptr<Device> m_device;
+};
+
+} /* namespace hailort */
+
+#endif /* _DEVICE_API_HPP_ */
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file hef_api.cpp
+ * @brief implementation of binding to an HEF class, and network_group usage over Python.
+ *
+ * TODO: doc
+ **/
+
+#include "hef_api.hpp"
+
+
+namespace hailort
+{
+
+HefWrapper::HefWrapper(const std::string &hef_path)
+{
+ auto hef_expected = Hef::create(hef_path);
+ VALIDATE_EXPECTED(hef_expected);
+
+ hef = make_unique_nothrow<Hef>(hef_expected.release());
+ if (nullptr == hef) {
+ THROW_STATUS_ERROR(HAILO_OUT_OF_HOST_MEMORY);
+ }
+}
+
+HefWrapper::HefWrapper(const MemoryView &hef_buffer)
+{
+ auto hef_expected = Hef::create(hef_buffer);
+ VALIDATE_EXPECTED(hef_expected);
+
+ hef = make_unique_nothrow<Hef>(hef_expected.release());
+ if (nullptr == hef) {
+ THROW_STATUS_ERROR(HAILO_OUT_OF_HOST_MEMORY);
+ }
+}
+
+HefWrapper HefWrapper::create_from_buffer(py::bytes data)
+{
+ return HefWrapper(MemoryView((uint8_t*)std::string(data).c_str(), std::string(data).size()));
+}
+
+HefWrapper HefWrapper::create_from_file(const std::string &hef_path)
+{
+ return HefWrapper(hef_path);
+}
+
+py::list HefWrapper::get_network_group_names()
+{
+ return py::cast(hef->get_network_groups_names());
+}
+
+py::list HefWrapper::get_network_groups_infos()
+{
+ auto network_group_infos = hef->get_network_groups_infos();
+ VALIDATE_EXPECTED(network_group_infos);
+ return py::cast(network_group_infos.release());
+}
+
+py::list HefWrapper::get_sorted_output_names(std::string net_group_name)
+{
+ auto names_list = hef->get_sorted_output_names(net_group_name);
+ VALIDATE_EXPECTED(names_list);
+
+ return py::cast(names_list.release());
+}
+
+float64_t HefWrapper::get_bottleneck_fps(const std::string &net_group_name)
+{
+ Expected<float64_t> bottleneck_fps = hef->get_bottleneck_fps(net_group_name);
+ VALIDATE_EXPECTED(bottleneck_fps);
+ return bottleneck_fps.release();
+}
+
+py::dict HefWrapper::get_udp_rates_dict(const std::string &net_group_name, uint32_t fps, uint32_t max_supported_rate_bytes)
+{
+ auto rate_calculator = NetworkUdpRateCalculator::create(hef.release(), net_group_name);
+ VALIDATE_EXPECTED(rate_calculator);
+ auto rates_per_name = rate_calculator.value().calculate_inputs_bandwith(fps, max_supported_rate_bytes);
+ VALIDATE_EXPECTED(rates_per_name);
+ return py::cast(rates_per_name.release());
+}
+
+py::list HefWrapper::get_original_names_from_vstream_name(const std::string &vstream_name, const std::string &net_group_name)
+{
+ auto results = hef->get_original_names_from_vstream_name(vstream_name, net_group_name);
+ VALIDATE_EXPECTED(results);
+ return py::cast(results.release());
+}
+
+std::string HefWrapper::get_vstream_name_from_original_name(const std::string &original_name, const std::string &net_group_name)
+{
+ auto results = hef->get_vstream_name_from_original_name(original_name, net_group_name);
+ VALIDATE_EXPECTED(results);
+ return results.release();
+}
+
+py::list HefWrapper::get_stream_names_from_vstream_name(const std::string &vstream_name, const std::string &net_group_name)
+{
+ auto results = hef->get_stream_names_from_vstream_name(vstream_name, net_group_name);
+ VALIDATE_EXPECTED(results);
+ return py::cast(results.release());
+}
+
+py::list HefWrapper::get_vstream_names_from_stream_name(const std::string &stream_name, const std::string &net_group_name)
+{
+ auto results = hef->get_vstream_names_from_stream_name(stream_name, net_group_name);
+ VALIDATE_EXPECTED(results);
+ return py::cast(results.release());
+}
+
+py::dict HefWrapper::get_input_vstreams_params(const std::string &name, bool quantized, hailo_format_type_t format_type,
+ uint32_t timeout_ms, uint32_t queue_size)
+{
+ auto result = hef->make_input_vstream_params(name, quantized, format_type, timeout_ms, queue_size);
+ VALIDATE_EXPECTED(result);
+ return py::cast(result.value());
+}
+
+py::dict HefWrapper::get_output_vstreams_params(const std::string &name, bool quantized, hailo_format_type_t format_type,
+ uint32_t timeout_ms, uint32_t queue_size)
+{
+ auto result = hef->make_output_vstream_params(name, quantized, format_type, timeout_ms, queue_size);
+ VALIDATE_EXPECTED(result);
+ return py::cast(result.value());
+}
+
+py::list HefWrapper::get_input_vstream_infos(const std::string &name)
+{
+ auto result = hef->get_input_vstream_infos(name);
+ VALIDATE_EXPECTED(result);
+ return py::cast(result.value());
+}
+
+py::list HefWrapper::get_output_vstream_infos(const std::string &name)
+{
+ auto result = hef->get_output_vstream_infos(name);
+ VALIDATE_EXPECTED(result);
+ return py::cast(result.value());
+}
+
+py::list HefWrapper::get_all_vstream_infos(const std::string &name)
+{
+ auto result = hef->get_all_vstream_infos(name);
+ VALIDATE_EXPECTED(result);
+ return py::cast(result.value());
+}
+
+py::list HefWrapper::get_input_stream_infos(const std::string &name)
+{
+ auto result = hef->get_input_stream_infos(name);
+ VALIDATE_EXPECTED(result);
+ return py::cast(result.value());
+}
+
+py::list HefWrapper::get_output_stream_infos(const std::string &name)
+{
+ auto result = hef->get_output_stream_infos(name);
+ VALIDATE_EXPECTED(result);
+ return py::cast(result.value());
+}
+
+py::list HefWrapper::get_all_stream_infos(const std::string &name)
+{
+ auto result = hef->get_all_stream_infos(name);
+ VALIDATE_EXPECTED(result);
+ return py::cast(result.value());
+}
+
+py::dict HefWrapper::create_configure_params(hailo_stream_interface_t interface)
+{
+ auto configure_params = hef->create_configure_params(interface);
+ VALIDATE_EXPECTED(configure_params);
+
+ return py::cast(configure_params.release());
+}
+
+py::dict HefWrapper::create_configure_params_mipi_input(hailo_stream_interface_t output_interface,
+ const hailo_mipi_input_stream_params_t &mipi_params)
+{
+ auto configure_params = hef->create_configure_params_mipi_input(output_interface, mipi_params);
+ VALIDATE_EXPECTED(configure_params);
+
+ return py::cast(configure_params.release());
+}
+
+py::list HefWrapper::get_networks_names(const std::string &net_group_name)
+{
+ auto network_infos = hef->get_network_infos(net_group_name);
+ VALIDATE_EXPECTED(network_infos);
+
+ std::vector<std::string> res;
+ for (const auto &info : network_infos.value()) {
+ res.push_back(info.name);
+ }
+
+ return py::cast(res);
+}
+
+ActivatedAppContextManagerWrapper::ActivatedAppContextManagerWrapper(ConfiguredNetworkGroup &net_group,
+ const hailo_activate_network_group_params_t &network_group_params) :
+ m_net_group(net_group), m_network_group_params(network_group_params)
+ {}
+
+const ActivatedNetworkGroup& ActivatedAppContextManagerWrapper::enter()
+{
+ auto activated = m_net_group.activate(m_network_group_params);
+ VALIDATE_EXPECTED(activated);
+
+ m_activated_net_group = activated.release();
+
+ return std::ref(*m_activated_net_group);
+}
+
+void ActivatedAppContextManagerWrapper::exit()
+{
+ m_activated_net_group.reset();
+}
+
+void ActivatedAppContextManagerWrapper::add_to_python_module(py::module &m)
+{
+ py::class_<ActivatedAppContextManagerWrapper>(m, "ActivatedApp")
+ .def("__enter__", &ActivatedAppContextManagerWrapper::enter, py::return_value_policy::reference)
+ .def("__exit__", [&](ActivatedAppContextManagerWrapper &self, py::args) { self.exit(); })
+ ;
+}
+
+void HefWrapper::initialize_python_module(py::module &m)
+{
+ py::class_<HefWrapper>(m, "Hef")
+ .def("create_from_buffer", &HefWrapper::create_from_buffer)
+ .def("create_from_file", &HefWrapper::create_from_file)
+ .def("get_network_group_names", &HefWrapper::get_network_group_names)
+ .def("get_network_groups_infos", &HefWrapper::get_network_groups_infos)
+ .def("get_sorted_output_names", &HefWrapper::get_sorted_output_names)
+ .def("get_bottleneck_fps", &HefWrapper::get_bottleneck_fps)
+ .def("get_stream_names_from_vstream_name", &HefWrapper::get_stream_names_from_vstream_name)
+ .def("get_vstream_names_from_stream_name", &HefWrapper::get_vstream_names_from_stream_name)
+ .def("get_vstream_name_from_original_name", &HefWrapper::get_vstream_name_from_original_name)
+ .def("get_original_names_from_vstream_name", &HefWrapper::get_original_names_from_vstream_name)
+ .def("get_udp_rates_dict", &HefWrapper::get_udp_rates_dict)
+ .def("create_configure_params", &HefWrapper::create_configure_params)
+ .def("create_configure_params_mipi_input", &HefWrapper::create_configure_params_mipi_input)
+ .def("get_input_vstreams_params", &HefWrapper::get_input_vstreams_params)
+ .def("get_output_vstreams_params", &HefWrapper::get_output_vstreams_params)
+ .def("get_input_vstream_infos", &HefWrapper::get_input_vstream_infos)
+ .def("get_output_vstream_infos", &HefWrapper::get_output_vstream_infos)
+ .def("get_all_vstream_infos", &HefWrapper::get_all_vstream_infos)
+ .def("get_input_stream_infos", &HefWrapper::get_input_stream_infos)
+ .def("get_output_stream_infos", &HefWrapper::get_output_stream_infos)
+ .def("get_all_stream_infos", &HefWrapper::get_all_stream_infos)
+ .def("get_networks_names", &HefWrapper::get_networks_names)
+ ;
+
+ py::class_<ConfiguredNetworkGroup>(m, "ConfiguredNetworkGroup")
+ .def("get_name", [](ConfiguredNetworkGroup& self)
+ {
+ return self.get_network_group_name();
+ })
+ .def("get_default_streams_interface", [](ConfiguredNetworkGroup& self)
+ {
+ auto result = self.get_default_streams_interface();
+ VALIDATE_EXPECTED(result);
+ return result.value();
+ })
+ .def("activate", [](ConfiguredNetworkGroup& self,
+ const hailo_activate_network_group_params_t &network_group_params)
+ {
+ return ActivatedAppContextManagerWrapper(self, network_group_params);
+ })
+ .def("wait_for_activation", [](ConfiguredNetworkGroup& self, uint32_t timeout_ms)
+ {
+ auto status = self.wait_for_activation(std::chrono::milliseconds(timeout_ms));
+ VALIDATE_STATUS(status);
+ })
+ .def("InputVStreams", [](ConfiguredNetworkGroup &self, std::map<std::string, hailo_vstream_params_t> &input_vstreams_params)
+ {
+ return InputVStreamsWrapper::create(self, input_vstreams_params);
+ })
+ .def("OutputVStreams", [](ConfiguredNetworkGroup &self, std::map<std::string, hailo_vstream_params_t> &output_vstreams_params)
+ {
+ return OutputVStreamsWrapper::create(self, output_vstreams_params);
+ })
+ .def("get_udp_rates_dict", [](ConfiguredNetworkGroup& self, uint32_t fps, uint32_t max_supported_rate_bytes)
+ {
+ auto rate_calculator = NetworkUdpRateCalculator::create(self);
+ VALIDATE_EXPECTED(rate_calculator);
+
+ auto udp_input_streams = self.get_input_streams_by_interface(HAILO_STREAM_INTERFACE_ETH);
+ auto results = rate_calculator->get_udp_ports_rates_dict(udp_input_streams,
+ fps, max_supported_rate_bytes);
+ VALIDATE_EXPECTED(results);
+
+ return py::cast(results.value());
+ })
+ ;
+
+ ActivatedAppContextManagerWrapper::add_to_python_module(m);
+
+ py::class_<ActivatedNetworkGroup>(m, "ActivatedNetworkGroup")
+ .def("get_intermediate_buffer", [](ActivatedNetworkGroup& self, uint8_t src_context_index,
+ uint8_t src_stream_index)
+ {
+ auto buff = self.get_intermediate_buffer(std::make_pair(src_context_index, src_stream_index));
+ VALIDATE_EXPECTED(buff);
+
+ return py::bytes(reinterpret_cast<char*>(buff->data()), buff->size());
+ })
+ .def("get_invalid_frames_count", [](ActivatedNetworkGroup& self)
+ {
+ return self.get_invalid_frames_count();
+ })
+ ;
+}
+
+} /* namespace hailort */
#include "hailo/hef.hpp"
#include "hailo/network_rate_calculator.hpp"
+#include "hailo/network_group.hpp"
-#include "bindings_common.hpp"
#include "vstream_api.hpp"
#include "utils.hpp"
#include "common/logger_macros.hpp"
class HefWrapper {
public:
- HefWrapper(const std::string &hef_path)
- {
- auto hef_expected = Hef::create(hef_path);
- VALIDATE_EXPECTED(hef_expected);
-
- hef = make_unique_nothrow<Hef>(hef_expected.release());
- if (nullptr == hef) {
- THROW_STATUS_ERROR(HAILO_OUT_OF_HOST_MEMORY);
- }
- };
-
- HefWrapper(const MemoryView &hef_buffer)
- {
- auto hef_expected = Hef::create(hef_buffer);
- VALIDATE_EXPECTED(hef_expected);
-
- hef = make_unique_nothrow<Hef>(hef_expected.release());
- if (nullptr == hef) {
- THROW_STATUS_ERROR(HAILO_OUT_OF_HOST_MEMORY);
- }
- };
-
- static HefWrapper create_from_buffer(py::bytes data)
- {
- return HefWrapper(MemoryView((uint8_t*)std::string(data).c_str(), std::string(data).size()));
- }
-
- static HefWrapper create_from_file(const std::string &hef_path)
- {
- return HefWrapper(hef_path);
- }
-
- const std::unique_ptr<Hef>& hef_ptr() const
- {
- return hef;
- }
-
- py::list get_network_group_names()
- {
- return py::cast(hef->get_network_groups_names());
- }
-
- py::list get_network_groups_infos()
- {
- auto network_group_infos = hef->get_network_groups_infos();
- VALIDATE_EXPECTED(network_group_infos);
- return py::cast(network_group_infos.release());
- }
-
- py::list get_sorted_output_names(std::string net_group_name)
- {
- auto names_list = hef->get_sorted_output_names(net_group_name);
- VALIDATE_EXPECTED(names_list);
-
- return py::cast(names_list.release());
- };
-
- float64_t get_bottleneck_fps(const std::string &net_group_name)
- {
- Expected<float64_t> bottleneck_fps = hef->get_bottleneck_fps(net_group_name);
- VALIDATE_EXPECTED(bottleneck_fps);
- return bottleneck_fps.release();
- };
-
- py::dict get_udp_rates_dict(const std::string &net_group_name, uint32_t fps, uint32_t max_supported_rate_bytes)
- {
- auto rate_calculator = NetworkUdpRateCalculator::create(hef.release(), net_group_name);
- VALIDATE_EXPECTED(rate_calculator);
- auto rates_per_name = rate_calculator.value().calculate_inputs_bandwith(fps, max_supported_rate_bytes);
- VALIDATE_EXPECTED(rates_per_name);
- return py::cast(rates_per_name.release());
- };
-
- py::list get_original_names_from_stream_name(const std::string &stream_name, const std::string &net_group_name)
- {
- LOGGER__WARNING("'get_original_names_from_stream_name()' is deprecated. One should use get_original_names_from_vstream_name()");
- auto results = hef->get_vstream_names_from_stream_name(stream_name, net_group_name);
- VALIDATE_EXPECTED(results);
- return py::cast(results.release());
- };
-
- std::string get_stream_name_from_original_name(const std::string &original_name, const std::string &net_group_name)
- {
- LOGGER__WARNING("'get_stream_name_from_original_name()' is deprecated. One should use get_vstream_name_from_original_name()");
- auto results = hef->get_stream_names_from_vstream_name(original_name, net_group_name);
- VALIDATE_EXPECTED(results);
- return results.release()[0];
- };
-
- py::list get_original_names_from_vstream_name(const std::string &vstream_name, const std::string &net_group_name)
- {
- auto results = hef->get_original_names_from_vstream_name(vstream_name, net_group_name);
- VALIDATE_EXPECTED(results);
- return py::cast(results.release());
- };
-
- std::string get_vstream_name_from_original_name(const std::string &original_name, const std::string &net_group_name)
- {
- auto results = hef->get_vstream_name_from_original_name(original_name, net_group_name);
- VALIDATE_EXPECTED(results);
- return results.release();
- };
-
- py::list get_stream_names_from_vstream_name(const std::string &vstream_name, const std::string &net_group_name)
- {
- auto results = hef->get_stream_names_from_vstream_name(vstream_name, net_group_name);
- VALIDATE_EXPECTED(results);
- return py::cast(results.release());
- };
-
- py::list get_vstream_names_from_stream_name(const std::string &stream_name, const std::string &net_group_name)
- {
- auto results = hef->get_vstream_names_from_stream_name(stream_name, net_group_name);
- VALIDATE_EXPECTED(results);
- return py::cast(results.release());
- };
-
+ HefWrapper(const std::string &hef_path);
+ HefWrapper(const MemoryView &hef_buffer);
+ static HefWrapper create_from_buffer(py::bytes data);
+ static HefWrapper create_from_file(const std::string &hef_path);
+ py::list get_network_group_names();
+ py::list get_network_groups_infos();
+ py::list get_sorted_output_names(std::string net_group_name);
+ float64_t get_bottleneck_fps(const std::string &net_group_name);
+ py::dict get_udp_rates_dict(const std::string &net_group_name, uint32_t fps, uint32_t max_supported_rate_bytes);
+ py::list get_original_names_from_vstream_name(const std::string &vstream_name, const std::string &net_group_name);
+ std::string get_vstream_name_from_original_name(const std::string &original_name, const std::string &net_group_name);
+ py::list get_stream_names_from_vstream_name(const std::string &vstream_name, const std::string &net_group_name);
+ py::list get_vstream_names_from_stream_name(const std::string &stream_name, const std::string &net_group_name);
py::dict get_input_vstreams_params(const std::string &name, bool quantized, hailo_format_type_t format_type,
- uint32_t timeout_ms, uint32_t queue_size)
- {
- auto result = hef->make_input_vstream_params(name, quantized, format_type, timeout_ms, queue_size);
- VALIDATE_EXPECTED(result);
- return py::cast(result.value());
- };
-
+ uint32_t timeout_ms, uint32_t queue_size);
py::dict get_output_vstreams_params(const std::string &name, bool quantized, hailo_format_type_t format_type,
- uint32_t timeout_ms, uint32_t queue_size)
- {
- auto result = hef->make_output_vstream_params(name, quantized, format_type, timeout_ms, queue_size);
- VALIDATE_EXPECTED(result);
- return py::cast(result.value());
- };
+ uint32_t timeout_ms, uint32_t queue_size);
+ py::list get_input_vstream_infos(const std::string &name);
+ py::list get_output_vstream_infos(const std::string &name);
+ py::list get_all_vstream_infos(const std::string &name);
+ py::list get_input_stream_infos(const std::string &name);
+ py::list get_output_stream_infos(const std::string &name);
+ py::list get_all_stream_infos(const std::string &name);
+ py::dict create_configure_params(hailo_stream_interface_t interface);
- py::list get_input_vstream_infos(const std::string &name)
- {
- auto result = hef->get_input_vstream_infos(name);
- VALIDATE_EXPECTED(result);
- return py::cast(result.value());
- }
-
- py::list get_output_vstream_infos(const std::string &name)
- {
- auto result = hef->get_output_vstream_infos(name);
- VALIDATE_EXPECTED(result);
- return py::cast(result.value());
- }
-
- py::list get_all_vstream_infos(const std::string &name)
- {
- auto result = hef->get_all_vstream_infos(name);
- VALIDATE_EXPECTED(result);
- return py::cast(result.value());
- }
-
- py::list get_input_stream_infos(const std::string &name)
- {
- auto result = hef->get_input_stream_infos(name);
- VALIDATE_EXPECTED(result);
- return py::cast(result.value());
- }
-
- py::list get_output_stream_infos(const std::string &name)
- {
- auto result = hef->get_output_stream_infos(name);
- VALIDATE_EXPECTED(result);
- return py::cast(result.value());
- }
-
- py::list get_all_stream_infos(const std::string &name)
+ const std::unique_ptr<Hef>& hef_ptr() const
{
- auto result = hef->get_all_stream_infos(name);
- VALIDATE_EXPECTED(result);
- return py::cast(result.value());
+ return hef;
}
- py::dict create_configure_params(hailo_stream_interface_t interface)
- {
- auto configure_params = hef->create_configure_params(interface);
- VALIDATE_EXPECTED(configure_params);
-
- return py::cast(configure_params.release());
- };
-
py::dict create_configure_params_mipi_input(hailo_stream_interface_t output_interface,
- const hailo_mipi_input_stream_params_t &mipi_params)
- {
- auto configure_params = hef->create_configure_params_mipi_input(output_interface, mipi_params);
- VALIDATE_EXPECTED(configure_params);
-
- return py::cast(configure_params.release());
- };
-
- py::list get_networks_names(const std::string &net_group_name)
- {
- auto network_infos = hef->get_network_infos(net_group_name);
- VALIDATE_EXPECTED(network_infos);
-
- std::vector<std::string> res;
- for (const auto &info : network_infos.value()) {
- res.push_back(info.name);
- }
-
- return py::cast(res);
- };
+ const hailo_mipi_input_stream_params_t &mipi_params);
+ py::list get_networks_names(const std::string &net_group_name);
+ static void initialize_python_module(py::module &m);
private:
std::unique_ptr<Hef> hef;
{
public:
ActivatedAppContextManagerWrapper(ConfiguredNetworkGroup &net_group,
- const hailo_activate_network_group_params_t &network_group_params)
- : m_net_group(net_group),
- m_network_group_params(network_group_params) {}
-
- const ActivatedNetworkGroup& enter()
- {
- auto activated = m_net_group.activate(m_network_group_params);
- VALIDATE_EXPECTED(activated);
-
- m_activated_net_group = activated.release();
-
- return std::ref(*m_activated_net_group);
- }
-
- void exit()
- {
- m_activated_net_group.reset();
- }
-
- static void add_to_python_module(py::module &m)
- {
- py::class_<ActivatedAppContextManagerWrapper>(m, "ActivatedApp")
- .def("__enter__", &ActivatedAppContextManagerWrapper::enter, py::return_value_policy::reference)
- .def("__exit__", [&](ActivatedAppContextManagerWrapper &self, py::args) { self.exit(); })
- ;
- }
-
+ const hailo_activate_network_group_params_t &network_group_params);
+
+ const ActivatedNetworkGroup& enter();
+ void exit();
+ static void add_to_python_module(py::module &m);
private:
std::unique_ptr<ActivatedNetworkGroup> m_activated_net_group;
ConfiguredNetworkGroup &m_net_group;
hailo_activate_network_group_params_t m_network_group_params;
};
-void HEF_API_initialize_python_module(py::module &m)
-{
- py::class_<HefWrapper>(m, "Hef")
- .def("create_from_buffer", &HefWrapper::create_from_buffer)
- .def("create_from_file", &HefWrapper::create_from_file)
- .def("get_network_group_names", &HefWrapper::get_network_group_names)
- .def("get_network_groups_infos", &HefWrapper::get_network_groups_infos)
- .def("get_sorted_output_names", &HefWrapper::get_sorted_output_names)
- .def("get_bottleneck_fps", &HefWrapper::get_bottleneck_fps)
- .def("get_stream_name_from_original_name", &HefWrapper::get_stream_name_from_original_name) // deprecated
- .def("get_original_names_from_stream_name", &HefWrapper::get_original_names_from_stream_name) // deprecated
- .def("get_stream_names_from_vstream_name", &HefWrapper::get_stream_names_from_vstream_name)
- .def("get_vstream_names_from_stream_name", &HefWrapper::get_vstream_names_from_stream_name)
- .def("get_vstream_name_from_original_name", &HefWrapper::get_vstream_name_from_original_name)
- .def("get_original_names_from_vstream_name", &HefWrapper::get_original_names_from_vstream_name)
- .def("get_udp_rates_dict", &HefWrapper::get_udp_rates_dict)
- .def("create_configure_params", &HefWrapper::create_configure_params)
- .def("create_configure_params_mipi_input", &HefWrapper::create_configure_params_mipi_input)
- .def("get_input_vstreams_params", &HefWrapper::get_input_vstreams_params)
- .def("get_output_vstreams_params", &HefWrapper::get_output_vstreams_params)
- .def("get_input_vstream_infos", &HefWrapper::get_input_vstream_infos)
- .def("get_output_vstream_infos", &HefWrapper::get_output_vstream_infos)
- .def("get_all_vstream_infos", &HefWrapper::get_all_vstream_infos)
- .def("get_input_stream_infos", &HefWrapper::get_input_stream_infos)
- .def("get_output_stream_infos", &HefWrapper::get_output_stream_infos)
- .def("get_all_stream_infos", &HefWrapper::get_all_stream_infos)
- .def("get_networks_names", &HefWrapper::get_networks_names)
- ;
-
- py::class_<ConfiguredNetworkGroup>(m, "ConfiguredNetworkGroup")
- .def("get_name", [](ConfiguredNetworkGroup& self)
- {
- return self.get_network_group_name();
- })
- .def("get_default_streams_interface", [](ConfiguredNetworkGroup& self)
- {
- auto result = self.get_default_streams_interface();
- VALIDATE_EXPECTED(result);
- return result.value();
- })
- .def("activate", [](ConfiguredNetworkGroup& self,
- const hailo_activate_network_group_params_t &network_group_params)
- {
- return ActivatedAppContextManagerWrapper(self, network_group_params);
- })
- .def("wait_for_activation", [](ConfiguredNetworkGroup& self, uint32_t timeout_ms)
- {
- auto status = self.wait_for_activation(std::chrono::milliseconds(timeout_ms));
- VALIDATE_STATUS(status);
- })
- .def("InputVStreams", [](ConfiguredNetworkGroup &self, std::map<std::string, hailo_vstream_params_t> &input_vstreams_params)
- {
- return InputVStreamsWrapper::create(self, input_vstreams_params);
- })
- .def("OutputVStreams", [](ConfiguredNetworkGroup &self, std::map<std::string, hailo_vstream_params_t> &output_vstreams_params)
- {
- return OutputVStreamsWrapper::create(self, output_vstreams_params);
- })
- .def("get_udp_rates_dict", [](ConfiguredNetworkGroup& self, uint32_t fps, uint32_t max_supported_rate_bytes)
- {
- auto rate_calculator = NetworkUdpRateCalculator::create(self);
- VALIDATE_EXPECTED(rate_calculator);
-
- auto udp_input_streams = self.get_input_streams_by_interface(HAILO_STREAM_INTERFACE_ETH);
- auto results = rate_calculator->get_udp_ports_rates_dict(udp_input_streams,
- fps, max_supported_rate_bytes);
- VALIDATE_EXPECTED(results);
-
- return py::cast(results.value());
- })
- ;
-
- ActivatedAppContextManagerWrapper::add_to_python_module(m);
-
- py::class_<ActivatedNetworkGroup>(m, "ActivatedNetworkGroup")
- .def("get_intermediate_buffer", [](ActivatedNetworkGroup& self, uint8_t src_context_index,
- uint8_t src_stream_index)
- {
- auto buff = self.get_intermediate_buffer(std::make_pair(src_context_index, src_stream_index));
- VALIDATE_EXPECTED(buff);
-
- return py::bytes(reinterpret_cast<char*>(buff->data()), buff->size());
- })
- .def("get_invalid_frames_count", [](ActivatedNetworkGroup& self)
- {
- return self.get_invalid_frames_count();
- })
- ;
-}
-
} /* namespace hailort */
#endif /* HEF_API_HPP_ */
${HAILORT_SRCS_ABS}
)
+set_target_properties(_pyhailort_internal PROPERTIES
+ CXX_STANDARD 14
+ CXX_STANDARD_REQUIRED YES
+)
+
target_include_directories(_pyhailort_internal
PRIVATE
$<BUILD_INTERFACE:${PYHAILORT_DIR}>
$<BUILD_INTERFACE:${DRIVER_INC_DIR}>
)
-target_link_libraries(_pyhailort_internal PRIVATE libhailort hef_proto spdlog::spdlog readerwriterqueue)
+target_link_libraries(_pyhailort_internal PRIVATE libhailort hef_proto spdlog::spdlog readerwriterqueue microprofile)
if(WIN32)
target_link_libraries(_pyhailort_internal PRIVATE Ws2_32 Iphlpapi Shlwapi)
endif()
target_compile_options(_pyhailort_internal PRIVATE ${HAILORT_COMPILE_OPTIONS})
-exclude_archive_libs_symbols(_pyhailort_internal)
\ No newline at end of file
+exclude_archive_libs_symbols(_pyhailort_internal)
namespace hailort
{
-
-void ControlWrapper::set_clock_freq(uintptr_t device, uint32_t clock_freq)
+void ControlWrapper::set_clock_freq(DeviceWrapper &device, uint32_t clock_freq)
{
- VALIDATE_NOT_NULL(reinterpret_cast<Device*>(device));
- auto status = Control::set_clock_freq(*reinterpret_cast<Device*>(device), clock_freq);
+ auto status = Control::set_clock_freq(*device, clock_freq);
VALIDATE_STATUS(status);
}
-void ControlWrapper::close_all_streams(uintptr_t device)
+void ControlWrapper::close_all_streams(DeviceWrapper &device)
{
- hailo_status status = HAILO_UNINITIALIZED;
-
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::close_all_streams(*reinterpret_cast<Device *>(device));
+ auto status = Control::close_all_streams(*device);
VALIDATE_STATUS(status);
}
-void ControlWrapper::config_ahb_to_axi(uintptr_t device, bool use_64bit_data_only)
+void ControlWrapper::config_ahb_to_axi(DeviceWrapper &device, bool use_64bit_data_only)
{
- hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__config_core_top_type_t config_type = CONTROL_PROTOCOL__CONFIG_CORE_TOP_TYPE_AHB_TO_AXI;
CONTROL_PROTOCOL__config_core_top_params_t params = {0};
params.ahb_to_axi.enable_use_64bit_data_only = use_64bit_data_only;
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::config_core_top(*reinterpret_cast<Device *>(device), config_type, ¶ms);
+ auto status = Control::config_core_top(*device, config_type, ¶ms);
VALIDATE_STATUS(status);
-
- return;
}
-void ControlWrapper::phy_operation(uintptr_t device, CONTROL_PROTOCOL__phy_operation_t operation_type)
+void ControlWrapper::phy_operation(DeviceWrapper &device, CONTROL_PROTOCOL__phy_operation_t operation_type)
{
- hailo_status status = HAILO_UNINITIALIZED;
-
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::phy_operation(*reinterpret_cast<Device *>(device), operation_type);
+ auto status = Control::phy_operation(*device, operation_type);
VALIDATE_STATUS(status);
-
- return;
}
-uint32_t ControlWrapper::latency_measurement_read(uintptr_t device)
+uint32_t ControlWrapper::latency_measurement_read(DeviceWrapper &device)
{
- hailo_status status = HAILO_UNINITIALIZED;
uint32_t inbound_to_outbound_latency_nsec = 0;
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::latency_measurement_read(*reinterpret_cast<Device *>(device), &inbound_to_outbound_latency_nsec);
+ auto status = Control::latency_measurement_read(*device, &inbound_to_outbound_latency_nsec);
VALIDATE_STATUS(status);
return inbound_to_outbound_latency_nsec;
}
-void ControlWrapper::latency_measurement_config(uintptr_t device, uint8_t latency_measurement_en,
+void ControlWrapper::latency_measurement_config(DeviceWrapper &device, uint8_t latency_measurement_en,
uint32_t inbound_start_buffer_number, uint32_t outbound_stop_buffer_number, uint32_t inbound_stream_index,
uint32_t outbound_stream_index)
{
- hailo_status status = HAILO_UNINITIALIZED;
-
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::latency_measurement_config(*reinterpret_cast<Device *>(device), latency_measurement_en, inbound_start_buffer_number,
+ auto status = Control::latency_measurement_config(*device, latency_measurement_en, inbound_start_buffer_number,
outbound_stop_buffer_number, inbound_stream_index, outbound_stream_index);
VALIDATE_STATUS(status);
-
- return;
}
-void ControlWrapper::start_firmware_update(uintptr_t device)
+void ControlWrapper::start_firmware_update(DeviceWrapper &device)
{
- hailo_status status = HAILO_UNINITIALIZED;
-
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::start_firmware_update(*reinterpret_cast<Device *>(device));
+ auto status = Control::start_firmware_update(*device);
VALIDATE_STATUS(status);
-
- return;
}
-void ControlWrapper::finish_firmware_update(uintptr_t device)
+void ControlWrapper::finish_firmware_update(DeviceWrapper &device)
{
- hailo_status status = HAILO_UNINITIALIZED;
-
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::finish_firmware_update(*reinterpret_cast<Device *>(device));
+ auto status = Control::finish_firmware_update(*device);
VALIDATE_STATUS(status);
-
- return;
}
-void ControlWrapper::write_firmware_update(uintptr_t device, uint32_t offset, py::bytes data, uint32_t length)
+void ControlWrapper::write_firmware_update(DeviceWrapper &device, uint32_t offset, py::bytes data, uint32_t length)
{
- hailo_status status = HAILO_UNINITIALIZED;
-
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::write_firmware_update(*reinterpret_cast<Device *>(device), offset, (uint8_t*)std::string(data).c_str(), length);
+ auto status = Control::write_firmware_update(*device, offset, (uint8_t*)std::string(data).c_str(), length);
VALIDATE_STATUS(status);
-
- return;
}
-void ControlWrapper::validate_firmware_update(uintptr_t device, py::bytes md5_raw_data, uint32_t firmware_size)
+void ControlWrapper::validate_firmware_update(DeviceWrapper &device, py::bytes md5_raw_data, uint32_t firmware_size)
{
- hailo_status status = HAILO_UNINITIALIZED;
MD5_SUM_t expected_md5 = {0};
-
memcpy(&expected_md5, (uint8_t*)std::string(md5_raw_data).c_str(), sizeof(expected_md5));
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::validate_firmware_update(*reinterpret_cast<Device *>(device), &expected_md5, firmware_size);
+ auto status = Control::validate_firmware_update(*device, &expected_md5, firmware_size);
VALIDATE_STATUS(status);
-
- return;
}
-py::bytes ControlWrapper::sensor_get_config(uintptr_t device, uint32_t section_index, uint32_t offset, uint32_t data_length)
+py::bytes ControlWrapper::sensor_get_config(DeviceWrapper &device, uint32_t section_index, uint32_t offset, uint32_t data_length)
{
- hailo_status status = HAILO_UNINITIALIZED;
std::unique_ptr<std::string> response = make_unique_nothrow<std::string>(data_length, '\x00');
VALIDATE_NOT_NULL(response);
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::sensor_get_config(*reinterpret_cast<Device *>(device), section_index, offset, data_length,
- (uint8_t*)(response->data()));
-
+ auto status = Control::sensor_get_config(*device, section_index, offset, data_length, (uint8_t*)(response->data()));
VALIDATE_STATUS(status);
return *response;
}
-void ControlWrapper::idle_time_set_measurement(uintptr_t device, bool measurement_enable)
+void ControlWrapper::idle_time_set_measurement(DeviceWrapper &device, bool measurement_enable)
{
- hailo_status status = HAILO_UNINITIALIZED;
-
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::idle_time_set_measurement(*reinterpret_cast<Device *>(device), measurement_enable);
+ auto status = Control::idle_time_set_measurement(*device, measurement_enable);
VALIDATE_STATUS(status);
}
-uint64_t ControlWrapper::idle_time_get_measurement(uintptr_t device)
+uint64_t ControlWrapper::idle_time_get_measurement(DeviceWrapper &device)
{
- hailo_status status = HAILO_UNINITIALIZED;
uint64_t measurement = 0;
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::idle_time_get_measurement(*reinterpret_cast<Device *>(device), &measurement);
+ auto status = Control::idle_time_get_measurement(*device, &measurement);
VALIDATE_STATUS(status);
return measurement;
}
-void ControlWrapper::d2h_notification_manager_set_host_info(uintptr_t device, uint16_t host_port, uint32_t host_ip_address)
+void ControlWrapper::d2h_notification_manager_set_host_info(DeviceWrapper &device, uint16_t host_port, uint32_t host_ip_address)
{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- hailo_status status = Control::d2h_notification_manager_set_host_info(*reinterpret_cast<Device *>(device), host_port, host_ip_address);
+ auto status = Control::d2h_notification_manager_set_host_info(*device, host_port, host_ip_address);
VALIDATE_STATUS(status);
}
-void ControlWrapper::d2h_notification_manager_send_host_info_notification(uintptr_t device, uint8_t notification_priority)
+void ControlWrapper::d2h_notification_manager_send_host_info_notification(DeviceWrapper &device, uint8_t notification_priority)
{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- hailo_status status = Control::d2h_notification_manager_send_host_info_notification(*reinterpret_cast<Device *>(device), notification_priority);
+ auto status = Control::d2h_notification_manager_send_host_info_notification(*device, notification_priority);
VALIDATE_STATUS(status);
}
/* Context switch */
-void ControlWrapper::set_context_switch_breakpoint(uintptr_t device,
+void ControlWrapper::set_context_switch_breakpoint(DeviceWrapper &device,
uint8_t breakpoint_id,
bool break_at_any_network_group_index, uint8_t network_group_index,
bool break_at_any_batch_index, uint16_t batch_index,
bool break_at_any_context_index,uint8_t context_index,
bool break_at_any_action_index, uint16_t action_index)
{
- hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__context_switch_breakpoint_control_t breakpoint_control =
CONTROL_PROTOCOL__CONTEXT_SWITCH_BREAKPOINT_CONTROL_SET;
CONTROL_PROTOCOL__context_switch_breakpoint_data_t breakpoint_data = {
break_at_any_action_index,
action_index};
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::config_context_switch_breakpoint(*reinterpret_cast<Device *>(device), breakpoint_id,
- breakpoint_control, &breakpoint_data);
+ auto status = Control::config_context_switch_breakpoint(*device, breakpoint_id, breakpoint_control, &breakpoint_data);
VALIDATE_STATUS(status);
}
-void ControlWrapper::continue_context_switch_breakpoint(uintptr_t device, uint8_t breakpoint_id)
+void ControlWrapper::continue_context_switch_breakpoint(DeviceWrapper &device, uint8_t breakpoint_id)
{
- hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__context_switch_breakpoint_control_t breakpoint_control =
CONTROL_PROTOCOL__CONTEXT_SWITCH_BREAKPOINT_CONTROL_CONTINUE;
CONTROL_PROTOCOL__context_switch_breakpoint_data_t breakpoint_data = {false,0,false,0,false,0,false,0};
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::config_context_switch_breakpoint(*reinterpret_cast<Device *>(device), breakpoint_id,
+ auto status = Control::config_context_switch_breakpoint(*device, breakpoint_id,
breakpoint_control, &breakpoint_data);
VALIDATE_STATUS(status);
}
-void ControlWrapper::clear_context_switch_breakpoint(uintptr_t device, uint8_t breakpoint_id)
+void ControlWrapper::clear_context_switch_breakpoint(DeviceWrapper &device, uint8_t breakpoint_id)
{
- hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__context_switch_breakpoint_control_t breakpoint_control =
CONTROL_PROTOCOL__CONTEXT_SWITCH_BREAKPOINT_CONTROL_CLEAR;
CONTROL_PROTOCOL__context_switch_breakpoint_data_t breakpoint_data = {false,0,false,0,false,0,false,0};
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::config_context_switch_breakpoint(*reinterpret_cast<Device *>(device), breakpoint_id,
+ auto status = Control::config_context_switch_breakpoint(*device, breakpoint_id,
breakpoint_control, &breakpoint_data);
VALIDATE_STATUS(status);
}
-uint8_t ControlWrapper::get_context_switch_breakpoint_status(uintptr_t device, uint8_t breakpoint_id)
+uint8_t ControlWrapper::get_context_switch_breakpoint_status(DeviceWrapper &device, uint8_t breakpoint_id)
{
- hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__context_switch_debug_sys_status_t breakpoint_status =
CONTROL_PROTOCOL__CONTEXT_SWITCH_DEBUG_SYS_STATUS_COUNT;
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::get_context_switch_breakpoint_status(*reinterpret_cast<Device *>(device), breakpoint_id,
+ auto status = Control::get_context_switch_breakpoint_status(*device, breakpoint_id,
&breakpoint_status);
VALIDATE_STATUS(status);
return static_cast<uint8_t>(breakpoint_status);
}
-void ControlWrapper::config_context_switch_timestamp(uintptr_t device, uint16_t batch_index)
+void ControlWrapper::config_context_switch_timestamp(DeviceWrapper &device, uint16_t batch_index)
{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- hailo_status status = Control::config_context_switch_timestamp(*reinterpret_cast<Device *>(device), batch_index, true);
+ auto status = Control::config_context_switch_timestamp(*device, batch_index, true);
VALIDATE_STATUS(status);
}
-void ControlWrapper::remove_context_switch_timestamp_configuration(uintptr_t device)
+void ControlWrapper::remove_context_switch_timestamp_configuration(DeviceWrapper &device)
{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- hailo_status status = Control::config_context_switch_timestamp(*reinterpret_cast<Device *>(device), 0, false);
+ auto status = Control::config_context_switch_timestamp(*device, 0, false);
VALIDATE_STATUS(status);
}
-void ControlWrapper::enable_debugging(uintptr_t device, bool is_rma)
+void ControlWrapper::enable_debugging(DeviceWrapper &device, bool is_rma)
{
- hailo_status status = HAILO_UNINITIALIZED;
-
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- status = Control::enable_debugging(*reinterpret_cast<Device *>(device), is_rma);
+ auto status = Control::enable_debugging(*device, is_rma);
VALIDATE_STATUS(status);
}
#include "control.hpp"
#include "utils.hpp"
+#include "device_api.hpp"
+
#include <pybind11/pybind11.h>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
public:
static void add_to_python_module(py::module &m);
- static void set_clock_freq(uintptr_t device, uint32_t clock_freq);
- static void close_all_streams(uintptr_t device);
- static void config_ahb_to_axi(uintptr_t device, bool use_64bit_data_only);
- static void phy_operation(uintptr_t device, CONTROL_PROTOCOL__phy_operation_t operation_type);
- static uint32_t latency_measurement_read(uintptr_t device);
- static void latency_measurement_config(uintptr_t device, uint8_t latency_measurement_en,
+ static void set_clock_freq(DeviceWrapper &device, uint32_t clock_freq);
+ static void close_all_streams(DeviceWrapper &device);
+ static void config_ahb_to_axi(DeviceWrapper &device, bool use_64bit_data_only);
+ static void phy_operation(DeviceWrapper &device, CONTROL_PROTOCOL__phy_operation_t operation_type);
+ static uint32_t latency_measurement_read(DeviceWrapper &device);
+ static void latency_measurement_config(DeviceWrapper &device, uint8_t latency_measurement_en,
uint32_t inbound_start_buffer_number, uint32_t outbound_stop_buffer_number, uint32_t inbound_stream_index,
uint32_t outbound_stream_index);
- static void start_firmware_update(uintptr_t device);
- static void finish_firmware_update(uintptr_t device);
- static void write_firmware_update(uintptr_t device, uint32_t offset, py::bytes data, uint32_t length);
- static void validate_firmware_update(uintptr_t device, py::bytes md5_raw_data, uint32_t firmware_size);
- static py::bytes sensor_get_config(uintptr_t device, uint32_t section_index, uint32_t offset, uint32_t data_length);
- static void idle_time_set_measurement(uintptr_t device, bool measurement_enable);
- static uint64_t idle_time_get_measurement(uintptr_t device);
- static void d2h_notification_manager_set_host_info(uintptr_t device, uint16_t host_port, uint32_t host_ip_address);
- static void d2h_notification_manager_send_host_info_notification(uintptr_t device, uint8_t notification_priority);
- static void enable_debugging(uintptr_t device, bool is_rma);
+ static void start_firmware_update(DeviceWrapper &device);
+ static void finish_firmware_update(DeviceWrapper &device);
+ static void write_firmware_update(DeviceWrapper &device, uint32_t offset, py::bytes data, uint32_t length);
+ static void validate_firmware_update(DeviceWrapper &device, py::bytes md5_raw_data, uint32_t firmware_size);
+ static py::bytes sensor_get_config(DeviceWrapper &device, uint32_t section_index, uint32_t offset, uint32_t data_length);
+ static void idle_time_set_measurement(DeviceWrapper &device, bool measurement_enable);
+ static uint64_t idle_time_get_measurement(DeviceWrapper &device);
+ static void d2h_notification_manager_set_host_info(DeviceWrapper &device, uint16_t host_port, uint32_t host_ip_address);
+ static void d2h_notification_manager_send_host_info_notification(DeviceWrapper &device, uint8_t notification_priority);
+ static void enable_debugging(DeviceWrapper &device, bool is_rma);
/* Context switch */
- static void set_context_switch_breakpoint(uintptr_t device, uint8_t breakpoint_id,
+ static void set_context_switch_breakpoint(DeviceWrapper &device, uint8_t breakpoint_id,
bool break_at_any_network_group_index, uint8_t network_group_index,
bool break_at_any_batch_index, uint16_t batch_index,
bool break_at_any_context_index,uint8_t context_index,
bool break_at_any_action_index, uint16_t action_index);
- static void continue_context_switch_breakpoint(uintptr_t device, uint8_t breakpoint_id);
- static void clear_context_switch_breakpoint(uintptr_t device, uint8_t breakpoint_id);
- static uint8_t get_context_switch_breakpoint_status(uintptr_t device, uint8_t breakpoint_id);
- static void config_context_switch_timestamp(uintptr_t device, uint16_t batch_index);
- static void remove_context_switch_timestamp_configuration(uintptr_t device);
+ static void continue_context_switch_breakpoint(DeviceWrapper &device, uint8_t breakpoint_id);
+ static void clear_context_switch_breakpoint(DeviceWrapper &device, uint8_t breakpoint_id);
+ static uint8_t get_context_switch_breakpoint_status(DeviceWrapper &device, uint8_t breakpoint_id);
+ static void config_context_switch_timestamp(DeviceWrapper &device, uint16_t batch_index);
+ static void remove_context_switch_timestamp_configuration(DeviceWrapper &device);
};
} /* namespace hailort */
.def_readonly("buffer_indices", &LayerInfo::buffer_indices)
.def_readonly("core_bytes_per_buffer", &LayerInfo::core_bytes_per_buffer)
.def_readonly("core_buffers_per_frame", &LayerInfo::core_buffers_per_frame)
- .def_readonly("network_name", &LayerInfo::partial_network_name)
+ .def_readonly("network_name", &LayerInfo::network_name)
;
}
#include <pybind11/complex.h>
#include <pybind11/functional.h>
#include <vector>
+#include <exception>
using namespace std;
-#include "hailo/hailort.h"
-#include "hailo/device.hpp"
-#include "hailo/transform.hpp"
-#include "hailo/hef.hpp"
-#include "hailo/hailort_common.hpp"
-#include "hailo/quantization.hpp"
+#include "hailo/hailort.hpp"
#include "hef_api.hpp"
#include "vstream_api.hpp"
#include "vdevice_api.hpp"
+#include "device_api.hpp"
+
#include "utils.hpp"
#include "utils.h"
-#include "common/socket.hpp"
+#include "bindings_common.hpp"
+
#include "sensor_config_exports.h"
#include "hailort_defaults.hpp"
#if defined(__GNUC__)
#define MAX_HAILO_PACKET_SIZE (4*1024)
-
-class PowerMeasurementData {
- public:
- float32_t m_average_value;
- float32_t m_average_time_value_milliseconds;
- float32_t m_min_value;
- float32_t m_max_value;
- uint32_t m_total_number_of_samples;
- PowerMeasurementData(hailo_power_measurement_data_t &&c_power_data);
- bool equals(const PowerMeasurementData &other);
- static py::tuple get_state(const PowerMeasurementData &power_measurement_data);
- static PowerMeasurementData set_state(py::tuple t);
- const static uint32_t NUM_OF_MEMBERS = 5;
-};
-
-PowerMeasurementData::PowerMeasurementData(hailo_power_measurement_data_t &&c_power_data)
-{
- m_average_value = c_power_data.average_value;
- m_average_time_value_milliseconds = c_power_data.average_time_value_milliseconds;
- m_min_value = c_power_data.min_value;
- m_max_value = c_power_data.max_value;
- m_total_number_of_samples = c_power_data.total_number_of_samples;
-}
-
-/* Return a tuple that fully encodes the state of the object */
-py::tuple PowerMeasurementData::get_state(const PowerMeasurementData &power_measurement_data){
- return py::make_tuple(
- power_measurement_data.m_average_value,
- power_measurement_data.m_average_time_value_milliseconds,
- power_measurement_data.m_min_value,
- power_measurement_data.m_max_value,
- power_measurement_data.m_total_number_of_samples);
-}
-
-PowerMeasurementData PowerMeasurementData::set_state(py::tuple t){
- if (PowerMeasurementData::NUM_OF_MEMBERS != t.size())
- throw std::runtime_error("Invalid power measurement data state!");
-
- /* Create a new C++ instance */
- hailo_power_measurement_data_t data;
- data.average_value = t[0].cast<float32_t>();
- data.average_time_value_milliseconds = t[1].cast<float32_t>();
- data.min_value = t[2].cast<float32_t>();
- data.max_value = t[3].cast<float32_t>();
- data.total_number_of_samples = t[4].cast<uint32_t>();
- return PowerMeasurementData(std::move(data));
-}
-
-bool PowerMeasurementData::equals(const PowerMeasurementData &other) {
- return ((this->m_average_value == other.m_average_value) &&
- (this->m_average_time_value_milliseconds == other.m_average_time_value_milliseconds) &&
- (this->m_min_value == other.m_min_value) &&
- (this->m_max_value == other.m_max_value) &&
- (this->m_total_number_of_samples == other.m_total_number_of_samples));
-}
-
bool temperature_info_equals(hailo_chip_temperature_info_t &first, hailo_chip_temperature_info_t &second){
return ((first.ts0_temperature == second.ts0_temperature) &&
(first.ts1_temperature == second.ts1_temperature) &&
}
class UdpScan {
public:
- UdpScan();
+ UdpScan() = default;
std::list<std::string> scan_devices(char *interface_name, uint32_t timeout_milliseconds);
private:
static const size_t m_max_number_of_devices = 100;
hailo_eth_device_info_t m_eth_device_infos[m_max_number_of_devices] = {};
};
-/* Device */
-// TODO HRT-5285: Change Python bindings of device class to use CPP API and move functionality to a new device module.
-uintptr_t create_eth_device(char *device_address, size_t device_address_length, uint16_t port,
- uint32_t timeout_milliseconds, uint8_t max_number_of_attempts)
+std::list<std::string> UdpScan::scan_devices(char* interface_name, uint32_t timeout_milliseconds)
{
hailo_status status = HAILO_UNINITIALIZED;
- hailo_device device = NULL;
- hailo_eth_device_info_t device_info = {};
-
- /* Validate address length */
- if (INET_ADDRSTRLEN < device_address_length) {
- EXIT_WITH_ERROR("device_address_length is invalid")
- }
-
- device_info.host_address.sin_family = AF_INET;
- device_info.host_address.sin_port = HAILO_ETH_PORT_ANY;
- status = Socket::pton(AF_INET, HAILO_ETH_ADDRESS_ANY, &(device_info.host_address.sin_addr));
- VALIDATE_STATUS(status);
+ size_t number_of_devices = 0;
+ std::list<std::string> device_addresses;
+ char textual_ip_address[INET_ADDRSTRLEN] = {0};
+ const char *inet_ntop_rc = NULL;
- device_info.device_address.sin_family = AF_INET;
- device_info.device_address.sin_port = port;
- status = Socket::pton(AF_INET, device_address, &(device_info.device_address.sin_addr));
+ status = hailo_scan_ethernet_devices(interface_name, m_eth_device_infos, 1, &number_of_devices, timeout_milliseconds);
VALIDATE_STATUS(status);
- device_info.timeout_millis = timeout_milliseconds;
- device_info.max_number_of_attempts = max_number_of_attempts;
- device_info.max_payload_size = HAILO_DEFAULT_ETH_MAX_PAYLOAD_SIZE;
-
- status = hailo_create_ethernet_device(&device_info, &device);
- VALIDATE_STATUS(status);
+ for(size_t i = 0; i<number_of_devices; ++i) {
+ inet_ntop_rc = inet_ntop(AF_INET, &(m_eth_device_infos[i].device_address.sin_addr), textual_ip_address, INET_ADDRSTRLEN);
+ if (NULL == inet_ntop_rc) {
+ EXIT_WITH_ERROR("Could not convert ip address to textual format (inet_ntop has failed)");
+ }
+ device_addresses.push_back(textual_ip_address);
+ }
- return (uintptr_t)device;
+ return device_addresses;
}
std::vector<hailo_pcie_device_info_t> scan_pcie_devices(void)
return scan_result.release();
}
-uintptr_t create_pcie_device(hailo_pcie_device_info_t *device_info)
-{
- hailo_device device = NULL;
- hailo_status status = hailo_create_pcie_device(device_info, &device);
- VALIDATE_STATUS(status);
-
- return (uintptr_t)device;
-}
-
-void release_device(uintptr_t device)
-{
- hailo_status status = HAILO_UNINITIALIZED;
-
- status = hailo_release_device((hailo_device)device);
- VALIDATE_STATUS(status);
-
- return;
-}
-
-uintptr_t get_hlpcie_device(uintptr_t hailort_device)
-{
- return hailort_device;
-}
-
-/* Controls */
-hailo_device_identity_t identify(uintptr_t device)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto board_info = reinterpret_cast<Device *>(device)->identify();
- VALIDATE_EXPECTED(board_info);
-
- return board_info.release();
-}
-
-hailo_core_information_t core_identify(uintptr_t device)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto core_info = reinterpret_cast<Device *>(device)->core_identify();
- VALIDATE_EXPECTED(core_info);
-
- return core_info.release();
-}
-
-void set_fw_logger(uintptr_t device, hailo_fw_logger_level_t level, uint32_t interface_mask)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device*>(device));
-
- auto status = reinterpret_cast<Device *>(device)->set_fw_logger(level, interface_mask);
- VALIDATE_STATUS(status);
-}
-
-void set_throttling_state(uintptr_t device, bool should_activate)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device*>(device));
-
- auto status = reinterpret_cast<Device *>(device)->set_throttling_state(should_activate);
- VALIDATE_STATUS(status);
-}
-
-bool get_throttling_state(uintptr_t device)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device*>(device));
-
- auto is_active_expected = reinterpret_cast<Device *>(device)->get_throttling_state();
- VALIDATE_EXPECTED(is_active_expected);
-
- return is_active_expected.release();
-}
-
-void set_overcurrent_state(uintptr_t device, bool should_activate)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device*>(device));
-
- auto status = reinterpret_cast<Device*>(device)->set_overcurrent_state(should_activate);
- VALIDATE_STATUS(status);
-}
-
-bool get_overcurrent_state(uintptr_t device)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device*>(device));
-
- auto is_required_expected = reinterpret_cast<Device*>(device)->get_overcurrent_state();
- VALIDATE_EXPECTED(is_required_expected);
-
- return is_required_expected.release();
-}
-
-py::bytes read_memory(uintptr_t device, uint32_t address, uint32_t length)
-{
- std::unique_ptr<std::string> response = make_unique_nothrow<std::string>(length, '\x00');
- VALIDATE_NOT_NULL(response);
- VALIDATE_NOT_NULL(reinterpret_cast<Device*>(device));
-
- MemoryView data_view(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(response->data())), length);
- auto status = (reinterpret_cast<Device*>(device))->read_memory(address, data_view);
- VALIDATE_STATUS(status);
-
- return *response;
-}
-
-void write_memory(uintptr_t device, uint32_t address, py::bytes data, uint32_t length)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device*>(device));
-
- auto status = (reinterpret_cast<Device*>(device))->write_memory(address, MemoryView(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(std::string(data).c_str())), length));
- VALIDATE_STATUS(status);
-
- return;
-}
-
-void test_chip_memories(uintptr_t device)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- hailo_status status = reinterpret_cast<Device *>(device)->test_chip_memories();
- VALIDATE_STATUS(status);
-}
-
-void i2c_write(uintptr_t device, hailo_i2c_slave_config_t *slave_config, uint32_t register_address, py::bytes data,
- uint32_t length)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- VALIDATE_NOT_NULL(slave_config);
-
- std::string data_str(data);
- MemoryView data_view = MemoryView::create_const(data_str.c_str(), length);
- auto status = reinterpret_cast<Device *>(device)->i2c_write(*slave_config, register_address, data_view);
- VALIDATE_STATUS(status);
-}
-
-py::bytes i2c_read(uintptr_t device, hailo_i2c_slave_config_t *slave_config, uint32_t register_address, uint32_t length)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- VALIDATE_NOT_NULL(slave_config);
-
- std::unique_ptr<std::string> response = make_unique_nothrow<std::string>(length, '\x00');
- VALIDATE_NOT_NULL(response);
-
- MemoryView data_view(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(response->data())), length);
- auto status = reinterpret_cast<Device *>(device)->i2c_read(*slave_config, register_address, data_view);
- VALIDATE_STATUS(status);
-
- return *response;
-}
-
-float32_t power_measurement(uintptr_t device, hailo_dvm_options_t dvm,
- hailo_power_measurement_types_t measurement_type)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto measurement = reinterpret_cast<Device *>(device)->power_measurement(dvm, measurement_type);
- VALIDATE_EXPECTED(measurement);
-
- return measurement.release();
-}
-
-void start_power_measurement(uintptr_t device, uint32_t delay_milliseconds,
- hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto status = reinterpret_cast<Device *>(device)->start_power_measurement(delay_milliseconds, averaging_factor,
- sampling_period);
- VALIDATE_STATUS(status);
-
- return;
-}
-
-void set_power_measurement(uintptr_t device, uint32_t index, hailo_dvm_options_t dvm,
- hailo_power_measurement_types_t measurement_type)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto status = reinterpret_cast<Device *>(device)->set_power_measurement(index, dvm, measurement_type);
- VALIDATE_STATUS(status);
-
- return;
-}
-
-PowerMeasurementData get_power_measurement(uintptr_t device, uint32_t index, bool should_clear)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto measurement_data = reinterpret_cast<Device *>(device)->get_power_measurement(index, should_clear);
- VALIDATE_EXPECTED(measurement_data);
-
- return PowerMeasurementData(measurement_data.release());
-}
-
-void stop_power_measurement(uintptr_t device)
-{
- hailo_status status = HAILO_UNINITIALIZED;
-
- status = hailo_stop_power_measurement((hailo_device)device);
- VALIDATE_STATUS(status);
-
- return;
-}
-
-void reset(uintptr_t device, hailo_reset_device_mode_t mode)
-{
- hailo_status status = HAILO_UNINITIALIZED;
-
- status = hailo_reset_device((hailo_device)device, mode);
- VALIDATE_STATUS(status);
-
- return;
-}
-
-hailo_fw_user_config_information_t examine_user_config(uintptr_t device)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto user_config_info = reinterpret_cast<Device *>(device)->examine_user_config();
- VALIDATE_EXPECTED(user_config_info);
-
- return user_config_info.release();
-}
-
-py::bytes read_user_config(uintptr_t device)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto config_buffer = reinterpret_cast<Device *>(device)->read_user_config();
- VALIDATE_EXPECTED(config_buffer);
-
- std::unique_ptr<std::string> response = make_unique_nothrow<std::string>(
- const_cast<char*>(reinterpret_cast<const char*>(config_buffer->data())), config_buffer->size());
- VALIDATE_NOT_NULL(response);
-
- return *response;
-}
-
-void write_user_config(uintptr_t device, py::bytes data)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- std::string data_str(data);
- MemoryView data_view = MemoryView::create_const(data_str.c_str(), data_str.size());
- auto status = reinterpret_cast<Device *>(device)->write_user_config(data_view);
- VALIDATE_STATUS(status);
-
- return;
-}
-
-void erase_user_config(uintptr_t device)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto status = reinterpret_cast<Device *>(device)->erase_user_config();
- VALIDATE_STATUS(status);
-
- return;
-}
-
-py::bytes read_board_config(uintptr_t device)
-{
- auto config_buffer = reinterpret_cast<Device *>(device)->read_board_config();
- VALIDATE_EXPECTED(config_buffer);
-
- std::unique_ptr<std::string> response = make_unique_nothrow<std::string>(
- const_cast<char*>(reinterpret_cast<const char*>(config_buffer->data())), config_buffer->size());
- VALIDATE_NOT_NULL(response);
-
- return *response;
-}
-
-void write_board_config(uintptr_t device, py::bytes data)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- std::string data_str(data);
- MemoryView data_view = MemoryView::create_const(data_str.c_str(), data_str.size());
- auto status = reinterpret_cast<Device *>(device)->write_board_config(data_view);
- VALIDATE_STATUS(status);
-
- return;
-}
-
-hailo_extended_device_information_t get_extended_device_information(uintptr_t device)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto extended_device_info = reinterpret_cast<Device *>(device)->get_extended_device_information();
- VALIDATE_EXPECTED(extended_device_info);
-
- return extended_device_info.release();
-}
-
-hailo_health_info_t get_health_information(uintptr_t device)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- auto health_info = reinterpret_cast<Device *>(device)->get_health_information();
- VALIDATE_EXPECTED(health_info);
-
- return health_info.release();
-}
-
-void sensor_store_config(uintptr_t device, uint32_t section_index, uint32_t reset_data_size, uint32_t sensor_type, const std::string &config_file_path,
- uint16_t config_height, uint16_t config_width, uint16_t config_fps, const std::string &config_name)
-{
- hailo_status status = HAILO_UNINITIALIZED;
- VALIDATE_NOT_NULL(reinterpret_cast<Device*>(device));
- status = (reinterpret_cast<Device*>(device))->store_sensor_config(section_index, static_cast<hailo_sensor_types_t>(sensor_type), reset_data_size, config_height, config_width,
- config_fps, config_file_path, config_name);
-
- VALIDATE_STATUS(status);
-
- return;
-}
-
-void store_isp_config(uintptr_t device, uint32_t reset_config_size, uint16_t config_height, uint16_t config_width, uint16_t config_fps,
- const std::string &isp_static_config_file_path, const std::string &isp_runtime_config_file_path, const std::string &config_name)
-{
- hailo_status status = HAILO_UNINITIALIZED;
- VALIDATE_NOT_NULL(reinterpret_cast<Device*>(device));
- status = (reinterpret_cast<Device*>(device))->store_isp_config(reset_config_size, config_height, config_width, config_fps,
- isp_static_config_file_path, isp_runtime_config_file_path, config_name);
- VALIDATE_STATUS(status);
-
- return;
-}
-
-py::bytes sensor_get_sections_info(uintptr_t device)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto buffer = (reinterpret_cast<Device*>(device))->sensor_get_sections_info();
- VALIDATE_EXPECTED(buffer);
-
- std::unique_ptr<std::string> response = make_unique_nothrow<std::string>(
- const_cast<char*>(reinterpret_cast<const char*>(buffer->data())), buffer->size());
- VALIDATE_NOT_NULL(response);
-
- return *response;
-}
-
-void sensor_set_i2c_bus_index(uintptr_t device, uint32_t sensor_type, uint32_t bus_index)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- hailo_status status = (reinterpret_cast<Device*>(device))->sensor_set_i2c_bus_index(
- static_cast<hailo_sensor_types_t>(sensor_type), bus_index);
- VALIDATE_STATUS(status);
-
- return;
-}
-
-void sensor_load_and_start_config(uintptr_t device, uint32_t section_index)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto status = (reinterpret_cast<Device*>(device))->sensor_load_and_start_config(section_index);
- VALIDATE_STATUS(status);
-
- return;
-}
-
-void sensor_reset(uintptr_t device, uint32_t section_index)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto status = (reinterpret_cast<Device*>(device))->sensor_reset(section_index);
- VALIDATE_STATUS(status);
-
- return;
-}
-
-void sensor_set_generic_i2c_slave(uintptr_t device, uint16_t slave_address,
- uint8_t register_address_size, uint8_t bus_index, uint8_t should_hold_bus, uint8_t endianness)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto status = (reinterpret_cast<Device*>(device))->sensor_set_generic_i2c_slave(slave_address, register_address_size,
- bus_index, should_hold_bus, endianness);
- VALIDATE_STATUS(status);
-
- return;
-}
-
-void firmware_update(uintptr_t device, py::bytes fw_bin, uint32_t fw_bin_length, bool should_reset)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- hailo_status status = reinterpret_cast<Device *>(device)->firmware_update(MemoryView::create_const(std::string(fw_bin).c_str(), fw_bin_length),
- should_reset);
- VALIDATE_STATUS(status);
-}
-
-void second_stage_update(uintptr_t device, py::bytes second_stage_bin, uint32_t second_stage_bin_length)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- hailo_status status = reinterpret_cast<Device *>(device)->second_stage_update((uint8_t *)std::string(second_stage_bin).c_str(),
- second_stage_bin_length);
- VALIDATE_STATUS(status);
-}
-
-py::list configure_device_from_hef(uintptr_t device, const HefWrapper &hef,
- const NetworkGroupsParamsMap &configure_params={})
-{
- if (nullptr == (void*)device) {
- EXIT_WITH_ERROR("Got NULL in parameter 'device'!");
- }
-
- auto network_groups = (reinterpret_cast<Device*>(device))->configure(*hef.hef_ptr(), configure_params);
- VALIDATE_EXPECTED(network_groups);
-
- py::list results;
- for (const auto &network_group : network_groups.value()) {
- results.append(network_group.get());
- }
-
- return results;
-}
-
// Quantization
void dequantize_output_buffer_from_uint8(py::array src_buffer, py::array dst_buffer, const hailo_format_type_t &dst_dtype,
uint32_t shape_size, const hailo_quant_info_t &quant_info)
break;
default:
LOGGER__ERROR("Output quantization isn't supported from src format type uint8 to dst format type = {}",
- convert_format_type_to_string(dst_dtype));
+ HailoRTBindingsCommon::convert_format_type_to_string(dst_dtype));
THROW_STATUS_ERROR(HAILO_INVALID_ARGUMENT);
break;
}
break;
default:
LOGGER__ERROR("Output quantization isn't supported from src dormat type uint16 to dst format type = {}",
- convert_format_type_to_string(dst_dtype));
+ HailoRTBindingsCommon::convert_format_type_to_string(dst_dtype));
THROW_STATUS_ERROR(HAILO_INVALID_ARGUMENT);
break;
}
break;
default:
LOGGER__ERROR("Output quantization isn't supported from src format type float32 to dst format type = {}",
- convert_format_type_to_string(dst_dtype));
+ HailoRTBindingsCommon::convert_format_type_to_string(dst_dtype));
THROW_STATUS_ERROR(HAILO_INVALID_ARGUMENT);
break;
}
break;
default:
LOGGER__ERROR("Output quantization isn't supported from src format type uint8 to dst format type = {}",
- convert_format_type_to_string(dst_dtype));
+ HailoRTBindingsCommon::convert_format_type_to_string(dst_dtype));
THROW_STATUS_ERROR(HAILO_INVALID_ARGUMENT);
break;
}
break;
default:
LOGGER__ERROR("Output quantization isn't supported from src dormat type uint16 to dst format type = {}",
- convert_format_type_to_string(dst_dtype));
+ HailoRTBindingsCommon::convert_format_type_to_string(dst_dtype));
THROW_STATUS_ERROR(HAILO_INVALID_ARGUMENT);
break;
}
break;
default:
LOGGER__ERROR("Output quantization isn't supported from src format type float32 to dst format type = {}",
- convert_format_type_to_string(dst_dtype));
+ HailoRTBindingsCommon::convert_format_type_to_string(dst_dtype));
THROW_STATUS_ERROR(HAILO_INVALID_ARGUMENT);
break;
}
dequantize_output_buffer_from_float32_in_place(dst_buffer, dst_dtype, shape_size, quant_info);
break;
default:
- LOGGER__ERROR("Unsupported src format type = {}", convert_format_type_to_string(dst_dtype));
+ LOGGER__ERROR("Unsupported src format type = {}", HailoRTBindingsCommon::convert_format_type_to_string(dst_dtype));
THROW_STATUS_ERROR(HAILO_INVALID_ARGUMENT);
break;
}
dequantize_output_buffer_from_float32(src_buffer, dst_buffer, dst_dtype, shape_size, quant_info);
break;
default:
- LOGGER__ERROR("Unsupported src format type = {}", convert_format_type_to_string(dst_dtype));
+ LOGGER__ERROR("Unsupported src format type = {}", HailoRTBindingsCommon::convert_format_type_to_string(dst_dtype));
THROW_STATUS_ERROR(HAILO_INVALID_ARGUMENT);
break;
}
static_cast<uint8_t*>(dst_buffer.mutable_data()), shape_size, quant_info);
break;
default:
- LOGGER__ERROR("Input quantization isn't supported from src format type uint8 to dst format type = {}", convert_format_type_to_string(dst_dtype));
+ LOGGER__ERROR("Input quantization isn't supported from src format type uint8 to dst format type = {}", HailoRTBindingsCommon::convert_format_type_to_string(dst_dtype));
THROW_STATUS_ERROR(HAILO_INVALID_ARGUMENT);
break;
}
break;
default:
LOGGER__ERROR("Input quantization isn't supported from src format type uint16 to dst format type = {}",
- convert_format_type_to_string(dst_dtype));
+ HailoRTBindingsCommon::convert_format_type_to_string(dst_dtype));
THROW_STATUS_ERROR(HAILO_INVALID_ARGUMENT);
break;
}
break;
default:
LOGGER__ERROR("Input quantization isn't supported from src format type float32 to dst format type = {}",
- convert_format_type_to_string(dst_dtype));
+ HailoRTBindingsCommon::convert_format_type_to_string(dst_dtype));
THROW_STATUS_ERROR(HAILO_INVALID_ARGUMENT);
break;
}
quantize_input_buffer_from_float32(src_buffer, dst_buffer, dst_dtype, shape_size, quant_info);
break;
default:
- LOGGER__ERROR("Input quantization isn't supported for src format type = {}", convert_format_type_to_string(dst_dtype));
+ LOGGER__ERROR("Input quantization isn't supported for src format type = {}", HailoRTBindingsCommon::convert_format_type_to_string(dst_dtype));
THROW_STATUS_ERROR(HAILO_INVALID_ARGUMENT);
break;
}
}
-void set_pause_frames(uintptr_t device, bool rx_pause_frames_enable)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto status = reinterpret_cast<Device *>(device)->set_pause_frames(rx_pause_frames_enable);
- VALIDATE_STATUS(status);
-
- return;
-}
-
-void wd_enable(uintptr_t device, hailo_cpu_id_t cpu_id)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- hailo_status status = reinterpret_cast<Device *>(device)->wd_enable(cpu_id);
- VALIDATE_STATUS(status);
-
- return;
-}
-
-void wd_disable(uintptr_t device, hailo_cpu_id_t cpu_id)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- hailo_status status = reinterpret_cast<Device *>(device)->wd_disable(cpu_id);
- VALIDATE_STATUS(status);
-
- return;
-}
-
-void wd_config(uintptr_t device, hailo_cpu_id_t cpu_id, uint32_t wd_cycles, hailo_watchdog_mode_t wd_mode)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
- auto status = reinterpret_cast<Device *>(device)->wd_config(cpu_id, wd_cycles, wd_mode);
- VALIDATE_STATUS(status);
-}
-
-uint32_t previous_system_state(uintptr_t device, hailo_cpu_id_t cpu_id)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto system_state = reinterpret_cast<Device *>(device)->previous_system_state(cpu_id);
- VALIDATE_EXPECTED(system_state);
-
- return system_state.release();
-}
-
-hailo_chip_temperature_info_t get_chip_temperature(uintptr_t device)
-{
- VALIDATE_NOT_NULL(reinterpret_cast<Device *>(device));
-
- auto temp_info = reinterpret_cast<Device *>(device)->get_chip_temperature();
- VALIDATE_EXPECTED(temp_info);
-
- return temp_info.release();
-}
-
-void set_input_stream_timeout(uintptr_t input_stream, uint32_t timeout_milis)
-{
- hailo_status status = hailo_set_input_stream_timeout((hailo_input_stream)input_stream, timeout_milis);
- VALIDATE_STATUS(status);
-}
-
-void set_output_stream_timeout(uintptr_t output_stream, uint32_t timeout_milis)
-{
- hailo_status status = hailo_set_output_stream_timeout((hailo_output_stream)output_stream, timeout_milis);
- VALIDATE_STATUS(status);
-}
-
-void set_notification_callback(uintptr_t device, const std::function<void(uintptr_t, const hailo_notification_t&, py::object)> &callback,
- hailo_notification_id_t notification_id, py::object opaque)
-{
- // we capture opaque and move it because when opaque goes out of score it will be deleted,
- // so capturing it ensures that it will not be deleted
- hailo_status status = ((Device*)device)->set_notification_callback(
- [callback, op = std::move(opaque)] (Device &device, const hailo_notification_t ¬ification, void* opaque) {
- (void)opaque;
- callback((uintptr_t)&device, notification, op);
- }, notification_id, nullptr);
- VALIDATE_STATUS(status);
-}
-
-void remove_notification_callback(uintptr_t device, hailo_notification_id_t notification_id)
-{
- hailo_status status = hailo_remove_notification_callback(reinterpret_cast<hailo_device>(device), notification_id);
- VALIDATE_STATUS(status);
-}
-
-UdpScan::UdpScan()
-{
-}
-
-std::list<std::string> UdpScan::scan_devices(char* interface_name, uint32_t timeout_milliseconds)
-{
- hailo_status status = HAILO_UNINITIALIZED;
- size_t number_of_devices = 0;
- std::list<std::string> device_addresses;
- char textual_ip_address[INET_ADDRSTRLEN] = {0};
- const char *inet_ntop_rc = NULL;
-
- status = hailo_scan_ethernet_devices(interface_name, m_eth_device_infos, 1, &number_of_devices, timeout_milliseconds);
- VALIDATE_STATUS(status);
-
- for(size_t i = 0; i<number_of_devices; ++i) {
- inet_ntop_rc = inet_ntop(AF_INET, &(m_eth_device_infos[i].device_address.sin_addr), textual_ip_address, INET_ADDRSTRLEN);
- if (NULL == inet_ntop_rc) {
- EXIT_WITH_ERROR("Could not convert ip address to textual format (inet_ntop has failed)");
- }
- device_addresses.push_back(textual_ip_address);
- }
-
- return device_addresses;
-}
-
-py::bytes read_log(uintptr_t device, size_t byte_count, hailo_cpu_id_t cpu_id)
-{
- std::string response;
-
- response.reserve(byte_count);
- response.resize(byte_count);
-
- MemoryView response_view ((&response[0]), byte_count);
- auto response_size_expected = ((Device*)device)->read_log(response_view, cpu_id);
- VALIDATE_EXPECTED(response_size_expected);
-
- response.resize(response_size_expected.release());
- return py::bytes(response);
-}
-
-void direct_write_memory(uintptr_t device, uint32_t address, py::bytes buffer)
-{
- const auto buffer_str = static_cast<std::string>(buffer);
- hailo_status status = ((Device*)device)->direct_write_memory(address, buffer_str.c_str(),
- (uint32_t) (buffer_str.length()));
- VALIDATE_STATUS(status);
-}
-
-py::bytes direct_read_memory(uintptr_t device, uint32_t address, uint32_t size)
-{
- std::string buffer_str;
-
- buffer_str.reserve(size);
- buffer_str.resize(size);
-
- hailo_status status = ((Device*)device)->direct_read_memory(address, (char*)buffer_str.c_str(), size);
- VALIDATE_STATUS(status);
-
- buffer_str.resize(size);
- return py::bytes(buffer_str);
-}
-
std::string get_status_message(uint32_t status_in)
{
auto status_str = hailo_get_status_message((hailo_status)status_in);
.def("reset_rate_limit", &TrafficControlUtilWrapper::reset_rate_limit)
.def_static("get_interface_name", [](const std::string &ip) {
return TrafficControlUtilWrapper::get_interface_name(ip);
- });
- ;
+ })
;
}
// End of temp hack for hlpcie
+static void validate_versions_match()
+{
+ hailo_version_t libhailort_version = {};
+ auto status = hailo_get_library_version(&libhailort_version);
+ if (HAILO_SUCCESS != status) {
+ throw std::logic_error("Failed to get libhailort version");
+ }
+
+ bool versions_match = ((HAILORT_MAJOR_VERSION == libhailort_version.major) &&
+ (HAILORT_MINOR_VERSION == libhailort_version.minor) &&
+ (HAILORT_REVISION_VERSION == libhailort_version.revision));
+ if (!versions_match) {
+ std::stringstream message;
+ message << "libhailort version (" <<
+ libhailort_version.major << "." << libhailort_version.minor << "." << libhailort_version.revision <<
+ ") does not match pyhailort version (" <<
+ HAILORT_MAJOR_VERSION << "." << HAILORT_MINOR_VERSION << "." << HAILORT_REVISION_VERSION << ")";
+ throw std::logic_error(message.str());
+ }
+}
+
PYBIND11_MODULE(_pyhailort, m) {
+ validate_versions_match();
+
m.def("get_status_message", &get_status_message);
- // Device
- m.def("create_eth_device", &create_eth_device);
- m.def("create_pcie_device", &create_pcie_device);
m.def("scan_pcie_devices", &scan_pcie_devices);
- m.def("release_device", &release_device);
- m.def("get_hlpcie_device", &get_hlpcie_device);
- // Controls
- m.def("identify", &identify);
- m.def("core_identify", &core_identify);
- m.def("set_fw_logger", &set_fw_logger);
- m.def("read_memory", &read_memory);
- m.def("write_memory", &write_memory);
- m.def("power_measurement", &power_measurement);
- m.def("start_power_measurement", &start_power_measurement);
- m.def("stop_power_measurement", &stop_power_measurement);
- m.def("set_power_measurement", &set_power_measurement);
- m.def("get_power_measurement", &get_power_measurement);
- m.def("firmware_update", &firmware_update);
- m.def("second_stage_update", &second_stage_update);
- m.def("examine_user_config", &examine_user_config);
- m.def("read_user_config", &read_user_config);
- m.def("write_user_config", &write_user_config);
- m.def("erase_user_config", &erase_user_config);
- m.def("read_board_config", &read_board_config);
- m.def("write_board_config", &write_board_config);
- m.def("i2c_write", &i2c_write);
- m.def("i2c_read", &i2c_read);
- m.def("sensor_store_config", &sensor_store_config);
- m.def("store_isp_config", &store_isp_config);
- m.def("sensor_set_i2c_bus_index", &sensor_set_i2c_bus_index);
- m.def("sensor_load_and_start_config", &sensor_load_and_start_config);
- m.def("sensor_reset", &sensor_reset);
- m.def("sensor_set_generic_i2c_slave", &sensor_set_generic_i2c_slave);
- m.def("sensor_get_sections_info", &sensor_get_sections_info);
- m.def("reset", &reset);
- m.def("wd_enable", &wd_enable);
- m.def("wd_disable", &wd_disable);
- m.def("wd_config", &wd_config);
- m.def("previous_system_state", &previous_system_state);
- m.def("get_chip_temperature", &get_chip_temperature);
- m.def("get_extended_device_information", &get_extended_device_information);
- m.def("set_pause_frames", &set_pause_frames);
- m.def("test_chip_memories", &test_chip_memories);
- m.def("_get_health_information", &get_health_information);
- m.def("set_throttling_state", &set_throttling_state);
- m.def("get_throttling_state", &get_throttling_state);
- m.def("_set_overcurrent_state", &set_overcurrent_state);
- m.def("_get_overcurrent_state", &get_overcurrent_state);
- //HEF
- m.def("configure_device_from_hef", &configure_device_from_hef);
- //Stream related
- m.def("set_input_stream_timeout", &set_input_stream_timeout);
- m.def("set_output_stream_timeout", &set_output_stream_timeout);
- m.def("set_notification_callback", &set_notification_callback);
- m.def("remove_notification_callback", &remove_notification_callback);
m.def("dequantize_output_buffer_in_place", &dequantize_output_buffer_in_place);
m.def("dequantize_output_buffer", &dequantize_output_buffer);
m.def("quantize_input_buffer", &quantize_input_buffer);
+ m.def("get_format_data_bytes", &HailoRTCommon::get_format_data_bytes);
+ m.def("get_dtype", &HailoRTBindingsCommon::get_dtype);
+
py::class_<hailo_pcie_device_info_t>(m, "PcieDeviceInfo")
.def(py::init<>())
.def_static("_parse", [](const std::string &device_info_str) {
.value("AVERAGE_1024", HAILO_AVERAGE_FACTOR_1024, "Each sample reflects a value of 1024 sub-samples.")
;
+ py::enum_<hailo_measurement_buffer_index_t>(m, "MeasurementBufferIndex", "Enum-like class representing all FW buffers for power measurements storing.")
+ .value("MEASUREMENT_BUFFER_INDEX_0", HAILO_MEASUREMENT_BUFFER_INDEX_0)
+ .value("MEASUREMENT_BUFFER_INDEX_1", HAILO_MEASUREMENT_BUFFER_INDEX_1)
+ .value("MEASUREMENT_BUFFER_INDEX_2", HAILO_MEASUREMENT_BUFFER_INDEX_2)
+ .value("MEASUREMENT_BUFFER_INDEX_3", HAILO_MEASUREMENT_BUFFER_INDEX_3)
+ ;
+
py::class_<hailo_notification_t>(m, "Notification")
.def_readonly("notification_id", &hailo_notification_t::id)
.def_readonly("sequence", &hailo_notification_t::sequence)
.def_readwrite("height", &hailo_3d_image_shape_t::height)
.def_readwrite("width", &hailo_3d_image_shape_t::width)
.def_readwrite("features", &hailo_3d_image_shape_t::features)
+ .def(py::pickle(
+ [](const hailo_3d_image_shape_t &shape) { // __getstate__
+ return py::make_tuple(
+ shape.height,
+ shape.width,
+ shape.features);
+ },
+ [](py::tuple t) { // __setstate__
+ hailo_3d_image_shape_t shape;
+ shape.height = t[0].cast<uint32_t>();
+ shape.width = t[1].cast<uint32_t>();
+ shape.features = t[2].cast<uint32_t>();
+ return shape;
+ }
+ ))
;
py::class_<hailo_nms_shape_t>(m, "NmsShape")
.def(py::init<>())
.def_readonly("number_of_classes", &hailo_nms_shape_t::number_of_classes)
.def_readonly("max_bboxes_per_class", &hailo_nms_shape_t::max_bboxes_per_class)
+ .def(py::pickle(
+ [](const hailo_nms_shape_t &nms_shape) { // __getstate__
+ return py::make_tuple(
+ nms_shape.number_of_classes,
+ nms_shape.max_bboxes_per_class);
+ },
+ [](py::tuple t) { // __setstate__
+ hailo_nms_shape_t nms_shape;
+ nms_shape.number_of_classes = t[0].cast<uint32_t>();
+ nms_shape.max_bboxes_per_class = t[1].cast<uint32_t>();
+ return nms_shape;
+ }
+ ))
;
py::class_<hailo_nms_info_t>(m, "NmsInfo")
.def_readwrite("qp_scale", &hailo_quant_info_t::qp_scale)
.def_readwrite("limvals_min", &hailo_quant_info_t::limvals_min)
.def_readwrite("limvals_max", &hailo_quant_info_t::limvals_max)
+ .def(py::pickle(
+ [](const hailo_quant_info_t &quant_info) { // __getstate__
+ return py::make_tuple(
+ quant_info.qp_zp,
+ quant_info.qp_scale,
+ quant_info.limvals_min,
+ quant_info.limvals_max);
+ },
+ [](py::tuple t) { // __setstate__
+ hailo_quant_info_t quant_info;
+ quant_info.qp_zp = t[0].cast<float32_t>();
+ quant_info.qp_scale = t[1].cast<float32_t>();
+ quant_info.limvals_min = t[2].cast<float32_t>();
+ quant_info.limvals_max = t[3].cast<float32_t>();
+ return quant_info;
+ }
+ ))
;
py::enum_<hailo_mipi_pixels_per_clock_t>(m, "MipiPixelsPerClock")
.def("__repr__", [](const hailo_vstream_info_t &self) {
return std::string("VStreamInfo(\"") + std::string(self.name) + std::string("\")");
})
+ .def(py::pickle(
+ [](const hailo_vstream_info_t &vstream_info) { // __getstate__
+ if (HAILO_FORMAT_ORDER_HAILO_NMS == vstream_info.format.order) {
+ return py::make_tuple(
+ vstream_info.name,
+ vstream_info.network_name,
+ vstream_info.direction,
+ vstream_info.format,
+ vstream_info.nms_shape,
+ vstream_info.quant_info);
+ }
+ else {
+ return py::make_tuple(
+ vstream_info.name,
+ vstream_info.network_name,
+ vstream_info.direction,
+ vstream_info.format,
+ vstream_info.shape,
+ vstream_info.quant_info);
+ }
+ },
+ [](py::tuple t) { // __setstate__
+ hailo_vstream_info_t vstream_info;
+ strcpy(vstream_info.name, t[0].cast<std::string>().c_str());
+ strcpy(vstream_info.network_name, t[1].cast<std::string>().c_str());
+ vstream_info.direction = t[2].cast<hailo_stream_direction_t>();
+ vstream_info.format = t[3].cast<hailo_format_t>();
+ if (HAILO_FORMAT_ORDER_HAILO_NMS == vstream_info.format.order) {
+ vstream_info.nms_shape = t[4].cast<hailo_nms_shape_t>();
+ }
+ else {
+ vstream_info.shape = t[4].cast<hailo_3d_image_shape_t>();
+ }
+ vstream_info.quant_info = t[5].cast<hailo_quant_info_t>();
+ return vstream_info;
+ }
+ ))
;
py::class_<hailo_stream_info_t>(m, "StreamInfo", py::module_local())
.def_static("MAX_ALIGNED_UDP_PAYLOAD_SIZE_RTP", []() { return 1472;} )
;
- m.def("read_log", &read_log, py::return_value_policy::move);
- m.def("direct_write_memory", &direct_write_memory);
- m.def("direct_read_memory", &direct_read_memory);
- m.def("get_format_data_bytes", &HailoRTCommon::get_format_data_bytes);
-
- HEF_API_initialize_python_module(m);
+ HefWrapper::initialize_python_module(m);
VStream_api_initialize_python_module(m);
VDevice_api_initialize_python_module(m);
+ DeviceWrapper::add_to_python_module(m);
+
#if defined(__GNUC__)
TrafficControlUtilWrapper::add_to_python_module(m);
#endif
-#ifdef VERSION_INFO
- m.attr("__version__") = VERSION_INFO;
-#else
- m.attr("__version__") = "dev";
-#endif
+ std::stringstream version;
+ version << HAILORT_MAJOR_VERSION << "." << HAILORT_MINOR_VERSION << "." << HAILORT_REVISION_VERSION;
+ m.attr("__version__") = version.str();
}
} /* namespace hailort */
#include "hailo/hef.hpp"
#include "hailo/vdevice.hpp"
-#include "bindings_common.hpp"
#include "utils.hpp"
#include "common/logger_macros.hpp"
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file vstream_api.cpp
+ * @brief Implementation of binding to virtual stream usage over Python.
+ **/
+
+#include "common/logger_macros.hpp"
+#include "common/utils.hpp"
+
+#include "vstream_api.hpp"
+#include "bindings_common.hpp"
+#include "utils.hpp"
+
+
+namespace hailort
+{
+
+void InputVStreamWrapper::add_to_python_module(py::module &m)
+{
+ py::class_<InputVStream, std::shared_ptr<InputVStream>>(m, "InputVStream")
+ .def("send", [](InputVStream &self, py::array data)
+ {
+ hailo_status status = self.write(
+ MemoryView(const_cast<void*>(reinterpret_cast<const void*>(data.data())), data.nbytes()));
+ VALIDATE_STATUS(status);
+ })
+ .def("flush", [](InputVStream &self)
+ {
+ hailo_status status = self.flush();
+ VALIDATE_STATUS(status);
+ })
+ .def_property_readonly("info", [](InputVStream &self)
+ {
+ return self.get_info();
+ })
+ .def_property_readonly("dtype", [](InputVStream &self)
+ {
+ const auto format_type = self.get_user_buffer_format().type;
+ return HailoRTBindingsCommon::get_dtype(format_type);
+ })
+ .def_property_readonly("shape", [](InputVStream &self)
+ {
+ return *py::array::ShapeContainer(HailoRTBindingsCommon::get_pybind_shape(self.get_info(), self.get_user_buffer_format()));
+ })
+ ;
+}
+
+InputVStreamsWrapper InputVStreamsWrapper::create(ConfiguredNetworkGroup &net_group,
+ const std::map<std::string, hailo_vstream_params_t> &input_vstreams_params)
+{
+ auto input_vstreams_expected = VStreamsBuilder::create_input_vstreams(net_group, input_vstreams_params);
+ VALIDATE_STATUS(input_vstreams_expected.status());
+
+ std::unordered_map<std::string, std::shared_ptr<InputVStream>> input_vstreams;
+ for (auto &input : input_vstreams_expected.value()) {
+ input_vstreams.emplace(input.name(), make_shared_nothrow<InputVStream>(std::move(input)));
+ }
+ return InputVStreamsWrapper(input_vstreams);
+}
+
+const InputVStreamsWrapper &InputVStreamsWrapper::enter()
+{
+ return std::ref(*this);
+}
+
+void InputVStreamsWrapper::exit()
+{
+ m_input_vstreams.clear();
+}
+
+std::shared_ptr<InputVStream> InputVStreamsWrapper::get_input_by_name(const std::string &name)
+{
+ auto input = m_input_vstreams.find(name);
+ if (m_input_vstreams.end() == input) {
+ LOGGER__ERROR("Input virtual stream for name={} not found", name);
+ THROW_STATUS_ERROR(HAILO_NOT_FOUND);
+ }
+
+ return input->second;
+}
+
+py::dict InputVStreamsWrapper::get_all_inputs()
+{
+ return py::cast(m_input_vstreams);
+}
+
+void InputVStreamsWrapper::clear()
+{
+ std::vector<std::reference_wrapper<InputVStream>> inputs;
+ inputs.reserve(m_input_vstreams.size());
+ for (auto &name_vstream_pair : m_input_vstreams) {
+ inputs.emplace_back(std::ref(*name_vstream_pair.second));
+ }
+
+ auto status = InputVStream::clear(inputs);
+ VALIDATE_STATUS(status);
+}
+
+void InputVStreamsWrapper::add_to_python_module(py::module &m)
+{
+ py::class_<InputVStreamsWrapper>(m, "InputVStreams")
+ .def(py::init(&InputVStreamsWrapper::create))
+ .def("get_input_by_name", &InputVStreamsWrapper::get_input_by_name)
+ .def("get_all_inputs", &InputVStreamsWrapper::get_all_inputs)
+ .def("clear", &InputVStreamsWrapper::clear)
+ .def("__enter__", &InputVStreamsWrapper::enter, py::return_value_policy::reference)
+ .def("__exit__", [&](InputVStreamsWrapper &self, py::args) { self.exit(); })
+ ;
+}
+
+InputVStreamsWrapper::InputVStreamsWrapper(std::unordered_map<std::string, std::shared_ptr<InputVStream>> &input_vstreams)
+ : m_input_vstreams(std::move(input_vstreams))
+{}
+
+py::dtype OutputVStreamWrapper::get_dtype(OutputVStream &self)
+{
+ const auto format_type = self.get_user_buffer_format().type;
+ return HailoRTBindingsCommon::get_dtype(format_type);
+}
+
+hailo_format_t OutputVStreamWrapper::get_user_buffer_format(OutputVStream &self)
+{
+ const auto format = self.get_user_buffer_format();
+ return format;
+}
+
+auto OutputVStreamWrapper::get_shape(OutputVStream &self)
+{
+ return *py::array::ShapeContainer(HailoRTBindingsCommon::get_pybind_shape(self.get_info(), self.get_user_buffer_format()));
+}
+
+void OutputVStreamWrapper::add_to_python_module(py::module &m)
+{
+ py::class_<OutputVStream, std::shared_ptr<OutputVStream>>(m, "OutputVStream")
+ .def("recv", [](OutputVStream &self)
+ {
+ auto buffer = Buffer::create(self.get_frame_size());
+ VALIDATE_STATUS(buffer.status());
+
+ hailo_status status = self.read(MemoryView(buffer->data(), buffer->size()));
+ VALIDATE_STATUS(status);
+
+ // Note: The ownership of the buffer is transferred to Python wrapped as a py::array.
+ // When the py::array isn't referenced anymore in Python and is destructed, the py::capsule's dtor
+ // is called too (and it deletes the raw buffer)
+ const auto unmanaged_addr = buffer.release().release();
+ return py::array(get_dtype(self), get_shape(self), unmanaged_addr,
+ py::capsule(unmanaged_addr, [](void *p) { delete reinterpret_cast<uint8_t*>(p); }));
+ })
+ .def_property_readonly("info", [](OutputVStream &self)
+ {
+ return self.get_info();
+ })
+ .def_property_readonly("dtype", &OutputVStreamWrapper::get_dtype)
+ .def_property_readonly("shape", &OutputVStreamWrapper::get_shape)
+ .def("get_user_buffer_format", &OutputVStreamWrapper::get_user_buffer_format)
+ ;
+}
+
+OutputVStreamsWrapper OutputVStreamsWrapper::create(ConfiguredNetworkGroup &net_group,
+ const std::map<std::string, hailo_vstream_params_t> &output_vstreams_params)
+{
+ auto output_vstreams_expected = VStreamsBuilder::create_output_vstreams(net_group, output_vstreams_params);
+ VALIDATE_STATUS(output_vstreams_expected.status());
+
+ std::unordered_map<std::string, std::shared_ptr<OutputVStream>> output_vstreams;
+ for (auto &output : output_vstreams_expected.value()) {
+ output_vstreams.emplace(output.name(), make_shared_nothrow<OutputVStream>(std::move(output)));
+ }
+ return OutputVStreamsWrapper(output_vstreams);
+}
+
+std::shared_ptr<OutputVStream> OutputVStreamsWrapper::get_output_by_name(const std::string &name)
+{
+ auto output = m_output_vstreams.find(name);
+ if (m_output_vstreams.end() == output) {
+ LOGGER__ERROR("Output virtual stream for name={} not found", name);
+ THROW_STATUS_ERROR(HAILO_NOT_FOUND);
+ }
+
+ return output->second;
+}
+
+const OutputVStreamsWrapper &OutputVStreamsWrapper::enter()
+{
+ return std::ref(*this);
+}
+
+void OutputVStreamsWrapper::exit()
+{
+ m_output_vstreams.clear();
+}
+
+py::dict OutputVStreamsWrapper::get_all_outputs()
+{
+ return py::cast(m_output_vstreams);
+}
+
+void OutputVStreamsWrapper::clear()
+{
+ std::vector<std::reference_wrapper<OutputVStream>> outputs;
+ outputs.reserve(m_output_vstreams.size());
+ for (auto &name_vstream_pair : m_output_vstreams) {
+ outputs.emplace_back(std::ref(*name_vstream_pair.second));
+ }
+
+ auto status = OutputVStream::clear(outputs);
+ VALIDATE_STATUS(status);
+}
+
+void OutputVStreamsWrapper::add_to_python_module(py::module &m)
+{
+ py::class_<OutputVStreamsWrapper>(m, "OutputVStreams")
+ .def(py::init(&OutputVStreamsWrapper::create))
+ .def("get_output_by_name", &OutputVStreamsWrapper::get_output_by_name)
+ .def("get_all_outputs", &OutputVStreamsWrapper::get_all_outputs)
+ .def("clear", &OutputVStreamsWrapper::clear)
+ .def("__enter__", &OutputVStreamsWrapper::enter, py::return_value_policy::reference)
+ .def("__exit__", [&](OutputVStreamsWrapper &self, py::args) { self.exit(); })
+ ;
+}
+
+OutputVStreamsWrapper::OutputVStreamsWrapper(std::unordered_map<std::string, std::shared_ptr<OutputVStream>> &output_vstreams)
+ : m_output_vstreams(std::move(output_vstreams))
+{}
+
+InferVStreamsWrapper InferVStreamsWrapper::create(ConfiguredNetworkGroup &network_group,
+ const std::map<std::string, hailo_vstream_params_t> &input_vstreams_params,
+ const std::map<std::string, hailo_vstream_params_t> &output_vstreams_params)
+{
+ auto infer_pipeline = InferVStreams::create(network_group, input_vstreams_params, output_vstreams_params);
+ VALIDATE_EXPECTED(infer_pipeline);
+ auto infer_vstream_ptr = make_shared_nothrow<InferVStreams>(std::move(infer_pipeline.value()));
+
+ return InferVStreamsWrapper(infer_vstream_ptr);
+}
+
+void InferVStreamsWrapper::infer(std::map<std::string, py::array> input_data, std::map<std::string, py::array> output_data,
+ size_t batch_size)
+{
+ std::map<std::string, MemoryView> input_data_c;
+ std::map<std::string, MemoryView> output_data_c;
+
+ for (auto& name_pair : input_data) {
+ input_data_c.emplace(name_pair.first, MemoryView(name_pair.second.mutable_data(),
+ static_cast<size_t>(name_pair.second.nbytes())));
+ }
+
+ for (auto& name_pair : output_data) {
+ output_data_c.emplace(name_pair.first, MemoryView(name_pair.second.mutable_data(),
+ static_cast<size_t>(name_pair.second.nbytes())));
+ }
+
+ hailo_status status = m_infer_pipeline->infer(input_data_c, output_data_c, batch_size);
+ VALIDATE_STATUS(status);
+}
+
+py::dtype InferVStreamsWrapper::get_host_dtype(const std::string &stream_name)
+{
+ auto input = m_infer_pipeline->get_input_by_name(stream_name);
+ if (HAILO_SUCCESS == input.status()) {
+ return HailoRTBindingsCommon::get_dtype(input->get().get_user_buffer_format().type);
+ } else if (HAILO_NOT_FOUND != input.status()) {
+ THROW_STATUS_ERROR(input.status());
+ }
+ auto output = m_infer_pipeline->get_output_by_name(stream_name);
+ VALIDATE_EXPECTED(output);
+
+ return HailoRTBindingsCommon::get_dtype(output->get().get_user_buffer_format().type);
+}
+
+hailo_format_t InferVStreamsWrapper::get_user_buffer_format(const std::string &stream_name)
+{
+ auto input = m_infer_pipeline->get_input_by_name(stream_name);
+ if (HAILO_SUCCESS == input.status()) {
+ return input->get().get_user_buffer_format();
+ } else if (HAILO_NOT_FOUND != input.status()) {
+ THROW_STATUS_ERROR(input.status());
+ }
+ auto output = m_infer_pipeline->get_output_by_name(stream_name);
+ VALIDATE_EXPECTED(output);
+
+ return output->get().get_user_buffer_format();
+}
+
+std::vector<size_t> InferVStreamsWrapper::get_shape(const std::string &stream_name)
+{
+ auto input = m_infer_pipeline->get_input_by_name(stream_name);
+ if (HAILO_SUCCESS == input.status()) {
+ return HailoRTBindingsCommon::get_pybind_shape(input->get().get_info(), input->get().get_user_buffer_format());
+ }
+
+ auto output = m_infer_pipeline->get_output_by_name(stream_name);
+ if (HAILO_SUCCESS == output.status()) {
+ return HailoRTBindingsCommon::get_pybind_shape(output->get().get_info(), output->get().get_user_buffer_format());
+ }
+
+ LOGGER__ERROR("Stream {} not found", stream_name);
+ THROW_STATUS_ERROR(HAILO_NOT_FOUND);
+}
+
+void InferVStreamsWrapper::release()
+{
+ m_infer_pipeline.reset();
+}
+
+void InferVStreamsWrapper::add_to_python_module(py::module &m)
+{
+ py::class_<InferVStreamsWrapper>(m, "InferVStreams")
+ .def(py::init(&InferVStreamsWrapper::create))
+ .def("get_host_dtype", &InferVStreamsWrapper::get_host_dtype)
+ .def("get_shape", &InferVStreamsWrapper::get_shape)
+ .def("get_user_buffer_format", &InferVStreamsWrapper::get_user_buffer_format)
+ .def("infer", &InferVStreamsWrapper::infer)
+ .def("release", [](InferVStreamsWrapper &self, py::args) { self.release(); })
+ ;
+}
+
+InferVStreamsWrapper::InferVStreamsWrapper(std::shared_ptr<InferVStreams> &infer_pipeline)
+ : m_infer_pipeline(std::move(infer_pipeline))
+{}
+
+void VStream_api_initialize_python_module(py::module &m)
+{
+ InputVStreamWrapper::add_to_python_module(m);
+ InputVStreamsWrapper::add_to_python_module(m);
+ OutputVStreamWrapper::add_to_python_module(m);
+ OutputVStreamsWrapper::add_to_python_module(m);
+ InferVStreamsWrapper::add_to_python_module(m);
+}
+
+} /* namespace hailort */
#include "common/utils.hpp"
#include "hailo/vstream.hpp"
#include "hailo/inference_pipeline.hpp"
-#include "bindings_common.hpp"
#include "utils.hpp"
#include <pybind11/pybind11.h>
class InputVStreamWrapper final
{
public:
- static void add_to_python_module(py::module &m)
- {
- py::class_<InputVStream, std::shared_ptr<InputVStream>>(m, "InputVStream")
- .def("send", [](InputVStream &self, py::array data)
- {
- hailo_status status = self.write(
- MemoryView(const_cast<void*>(reinterpret_cast<const void*>(data.data())), data.nbytes()));
- VALIDATE_STATUS(status);
- })
- .def("flush", [](InputVStream &self)
- {
- hailo_status status = self.flush();
- VALIDATE_STATUS(status);
- })
- .def_property_readonly("info", [](InputVStream &self)
- {
- return self.get_info();
- })
- .def_property_readonly("dtype", [](InputVStream &self)
- {
- const auto format_type = self.get_user_buffer_format().type;
- return py::dtype(convert_format_type_to_string(format_type));
- })
- .def_property_readonly("shape", [](InputVStream &self)
- {
- return *py::array::ShapeContainer(get_pybind_shape(self.get_info(), self.get_user_buffer_format()));
- })
- ;
- }
+ static void add_to_python_module(py::module &m);
};
class InputVStreamsWrapper final
{
public:
-
static InputVStreamsWrapper create(ConfiguredNetworkGroup &net_group,
- const std::map<std::string, hailo_vstream_params_t> &input_vstreams_params)
- {
- auto input_vstreams_expected = VStreamsBuilder::create_input_vstreams(net_group, input_vstreams_params);
- VALIDATE_STATUS(input_vstreams_expected.status());
-
- std::unordered_map<std::string, std::shared_ptr<InputVStream>> input_vstreams;
- for (auto &input : input_vstreams_expected.value()) {
- input_vstreams.emplace(input.name(), make_shared_nothrow<InputVStream>(std::move(input)));
- }
- return InputVStreamsWrapper(input_vstreams);
- }
-
- const InputVStreamsWrapper &enter()
- {
- return std::ref(*this);
- }
-
- void exit()
- {
- m_input_vstreams.clear();
- }
-
- std::shared_ptr<InputVStream> get_input_by_name(const std::string &name)
- {
- auto input = m_input_vstreams.find(name);
- if (m_input_vstreams.end() == input) {
- LOGGER__ERROR("Input virtual stream for name={} not found", name);
- THROW_STATUS_ERROR(HAILO_NOT_FOUND);
- }
-
- return input->second;
- }
-
- py::dict get_all_inputs()
- {
- return py::cast(m_input_vstreams);
- }
-
- void clear()
- {
- std::vector<std::reference_wrapper<InputVStream>> inputs;
- inputs.reserve(m_input_vstreams.size());
- for (auto &name_vstream_pair : m_input_vstreams) {
- inputs.emplace_back(std::ref(*name_vstream_pair.second));
- }
-
- auto status = InputVStream::clear(inputs);
- VALIDATE_STATUS(status);
- }
-
- static void add_to_python_module(py::module &m)
- {
- py::class_<InputVStreamsWrapper>(m, "InputVStreams")
- .def(py::init(&InputVStreamsWrapper::create))
- .def("get_input_by_name", &InputVStreamsWrapper::get_input_by_name)
- .def("get_all_inputs", &InputVStreamsWrapper::get_all_inputs)
- .def("clear", &InputVStreamsWrapper::clear)
- .def("__enter__", &InputVStreamsWrapper::enter, py::return_value_policy::reference)
- .def("__exit__", [&](InputVStreamsWrapper &self, py::args) { self.exit(); })
- ;
- }
+ const std::map<std::string, hailo_vstream_params_t> &input_vstreams_params);
+ const InputVStreamsWrapper &enter();
+ void exit();
+ std::shared_ptr<InputVStream> get_input_by_name(const std::string &name);
+ py::dict get_all_inputs();
+ void clear();
+ static void add_to_python_module(py::module &m);
private:
- InputVStreamsWrapper(std::unordered_map<std::string, std::shared_ptr<InputVStream>> &input_vstreams) :
- m_input_vstreams(std::move(input_vstreams))
- {}
-
+ InputVStreamsWrapper(std::unordered_map<std::string, std::shared_ptr<InputVStream>> &input_vstreams);
std::unordered_map<std::string, std::shared_ptr<InputVStream>> m_input_vstreams;
};
class OutputVStreamWrapper final
{
public:
-
- static py::dtype get_dtype(OutputVStream &self)
- {
- const auto format_type = self.get_user_buffer_format().type;
- return py::dtype(convert_format_type_to_string(format_type));
- }
-
- static hailo_format_t get_user_buffer_format(OutputVStream &self)
- {
- const auto format = self.get_user_buffer_format();
- return format;
- }
-
- static auto get_shape(OutputVStream &self)
- {
- return *py::array::ShapeContainer(get_pybind_shape(self.get_info(), self.get_user_buffer_format()));
- }
-
- static void add_to_python_module(py::module &m)
- {
- py::class_<OutputVStream, std::shared_ptr<OutputVStream>>(m, "OutputVStream")
- .def("recv", [](OutputVStream &self)
- {
- auto buffer = Buffer::create(self.get_frame_size());
- VALIDATE_STATUS(buffer.status());
-
- hailo_status status = self.read(MemoryView(buffer->data(), buffer->size()));
- VALIDATE_STATUS(status);
-
- // Note: The ownership of the buffer is transferred to Python wrapped as a py::array.
- // When the py::array isn't referenced anymore in Python and is destructed, the py::capsule's dtor
- // is called too (and it deletes the raw buffer)
- const auto unmanaged_addr = buffer.release().release();
- return py::array(get_dtype(self), get_shape(self), unmanaged_addr,
- py::capsule(unmanaged_addr, [](void *p) { delete reinterpret_cast<uint8_t*>(p); }));
- })
- .def_property_readonly("info", [](OutputVStream &self)
- {
- return self.get_info();
- })
- .def_property_readonly("dtype", &OutputVStreamWrapper::get_dtype)
- .def_property_readonly("shape", &OutputVStreamWrapper::get_shape)
- .def("get_user_buffer_format", &OutputVStreamWrapper::get_user_buffer_format)
- ;
- }
+ static py::dtype get_dtype(OutputVStream &self);
+ static hailo_format_t get_user_buffer_format(OutputVStream &self);
+ static auto get_shape(OutputVStream &self);
+ static void add_to_python_module(py::module &m);
};
class OutputVStreamsWrapper final
{
public:
-
static OutputVStreamsWrapper create(ConfiguredNetworkGroup &net_group,
- const std::map<std::string, hailo_vstream_params_t> &output_vstreams_params)
- {
- auto output_vstreams_expected = VStreamsBuilder::create_output_vstreams(net_group, output_vstreams_params);
- VALIDATE_STATUS(output_vstreams_expected.status());
-
- std::unordered_map<std::string, std::shared_ptr<OutputVStream>> output_vstreams;
- for (auto &output : output_vstreams_expected.value()) {
- output_vstreams.emplace(output.name(), make_shared_nothrow<OutputVStream>(std::move(output)));
- }
- return OutputVStreamsWrapper(output_vstreams);
- }
-
- std::shared_ptr<OutputVStream> get_output_by_name(const std::string &name)
- {
- auto output = m_output_vstreams.find(name);
- if (m_output_vstreams.end() == output) {
- LOGGER__ERROR("Output virtual stream for name={} not found", name);
- THROW_STATUS_ERROR(HAILO_NOT_FOUND);
- }
-
- return output->second;
- }
-
- const OutputVStreamsWrapper &enter()
- {
- return std::ref(*this);
- }
-
- void exit()
- {
- m_output_vstreams.clear();
- }
-
- py::dict get_all_outputs()
- {
- return py::cast(m_output_vstreams);
- }
-
- void clear()
- {
- std::vector<std::reference_wrapper<OutputVStream>> outputs;
- outputs.reserve(m_output_vstreams.size());
- for (auto &name_vstream_pair : m_output_vstreams) {
- outputs.emplace_back(std::ref(*name_vstream_pair.second));
- }
-
- auto status = OutputVStream::clear(outputs);
- VALIDATE_STATUS(status);
- }
-
- static void add_to_python_module(py::module &m)
- {
- py::class_<OutputVStreamsWrapper>(m, "OutputVStreams")
- .def(py::init(&OutputVStreamsWrapper::create))
- .def("get_output_by_name", &OutputVStreamsWrapper::get_output_by_name)
- .def("get_all_outputs", &OutputVStreamsWrapper::get_all_outputs)
- .def("clear", &OutputVStreamsWrapper::clear)
- .def("__enter__", &OutputVStreamsWrapper::enter, py::return_value_policy::reference)
- .def("__exit__", [&](OutputVStreamsWrapper &self, py::args) { self.exit(); })
- ;
- }
+ const std::map<std::string, hailo_vstream_params_t> &output_vstreams_params);
+ std::shared_ptr<OutputVStream> get_output_by_name(const std::string &name);
+ const OutputVStreamsWrapper &enter();
+ void exit();
+ py::dict get_all_outputs();
+ void clear();
+ static void add_to_python_module(py::module &m);
private:
- OutputVStreamsWrapper(std::unordered_map<std::string, std::shared_ptr<OutputVStream>> &output_vstreams) :
- m_output_vstreams(std::move(output_vstreams))
- {}
-
+ OutputVStreamsWrapper(std::unordered_map<std::string, std::shared_ptr<OutputVStream>> &output_vstreams);
std::unordered_map<std::string, std::shared_ptr<OutputVStream>> m_output_vstreams;
};
public:
static InferVStreamsWrapper create(ConfiguredNetworkGroup &network_group,
const std::map<std::string, hailo_vstream_params_t> &input_vstreams_params,
- const std::map<std::string, hailo_vstream_params_t> &output_vstreams_params)
- {
- auto infer_pipeline = InferVStreams::create(network_group, input_vstreams_params, output_vstreams_params);
- VALIDATE_EXPECTED(infer_pipeline);
- auto infer_vstream_ptr = make_shared_nothrow<InferVStreams>(std::move(infer_pipeline.value()));
-
- return InferVStreamsWrapper(infer_vstream_ptr);
- }
-
+ const std::map<std::string, hailo_vstream_params_t> &output_vstreams_params);
void infer(std::map<std::string, py::array> input_data, std::map<std::string, py::array> output_data,
- size_t batch_size)
- {
- std::map<std::string, MemoryView> input_data_c;
- std::map<std::string, MemoryView> output_data_c;
-
- for (auto& name_pair : input_data) {
- input_data_c.emplace(name_pair.first, MemoryView(name_pair.second.mutable_data(),
- static_cast<size_t>(name_pair.second.nbytes())));
- }
-
- for (auto& name_pair : output_data) {
- output_data_c.emplace(name_pair.first, MemoryView(name_pair.second.mutable_data(),
- static_cast<size_t>(name_pair.second.nbytes())));
- }
-
- hailo_status status = m_infer_pipeline->infer(input_data_c, output_data_c, batch_size);
- VALIDATE_STATUS(status);
- }
-
- py::dtype get_host_dtype(const std::string &stream_name)
- {
- auto input = m_infer_pipeline->get_input_by_name(stream_name);
- if (HAILO_SUCCESS == input.status()) {
- return py::dtype(convert_format_type_to_string(input->get().get_user_buffer_format().type));
- } else if (HAILO_NOT_FOUND != input.status()) {
- THROW_STATUS_ERROR(input.status());
- }
- auto output = m_infer_pipeline->get_output_by_name(stream_name);
- VALIDATE_EXPECTED(output);
-
- return py::dtype(convert_format_type_to_string(output->get().get_user_buffer_format().type));
- }
-
- hailo_format_t get_user_buffer_format(const std::string &stream_name)
- {
- auto input = m_infer_pipeline->get_input_by_name(stream_name);
- if (HAILO_SUCCESS == input.status()) {
- return input->get().get_user_buffer_format();
- } else if (HAILO_NOT_FOUND != input.status()) {
- THROW_STATUS_ERROR(input.status());
- }
- auto output = m_infer_pipeline->get_output_by_name(stream_name);
- VALIDATE_EXPECTED(output);
-
- return output->get().get_user_buffer_format();
- }
-
- std::vector<size_t> get_shape(const std::string &stream_name)
- {
- auto input = m_infer_pipeline->get_input_by_name(stream_name);
- if (HAILO_SUCCESS == input.status()) {
- return get_pybind_shape(input->get().get_info(), input->get().get_user_buffer_format());
- }
-
- auto output = m_infer_pipeline->get_output_by_name(stream_name);
- if (HAILO_SUCCESS == output.status()) {
- return get_pybind_shape(output->get().get_info(), output->get().get_user_buffer_format());
- }
-
- LOGGER__ERROR("Stream {} not found", stream_name);
- THROW_STATUS_ERROR(HAILO_NOT_FOUND);
- }
-
- void release()
- {
- m_infer_pipeline.reset();
- }
-
- static void add_to_python_module(py::module &m)
- {
- py::class_<InferVStreamsWrapper>(m, "InferVStreams")
- .def(py::init(&InferVStreamsWrapper::create))
- .def("get_host_dtype", &InferVStreamsWrapper::get_host_dtype)
- .def("get_shape", &InferVStreamsWrapper::get_shape)
- .def("get_user_buffer_format", &InferVStreamsWrapper::get_user_buffer_format)
- .def("infer", &InferVStreamsWrapper::infer)
- .def("release", [](InferVStreamsWrapper &self, py::args) { self.release(); })
- ;
- }
+ size_t batch_size);
+ py::dtype get_host_dtype(const std::string &stream_name);
+ hailo_format_t get_user_buffer_format(const std::string &stream_name);
+ std::vector<size_t> get_shape(const std::string &stream_name);
+ void release();
+ static void add_to_python_module(py::module &m);
private:
- InferVStreamsWrapper(std::shared_ptr<InferVStreams> &infer_pipeline) :
- m_infer_pipeline(std::move(infer_pipeline))
- {}
-
- std::shared_ptr<InferVStreams> m_infer_pipeline;
+ InferVStreamsWrapper(std::shared_ptr<InferVStreams> &infer_pipeline);
+
+ std::shared_ptr<InferVStreams> m_infer_pipeline;
};
-void VStream_api_initialize_python_module(py::module &m)
-{
- InputVStreamWrapper::add_to_python_module(m);
- InputVStreamsWrapper::add_to_python_module(m);
- OutputVStreamWrapper::add_to_python_module(m);
- OutputVStreamsWrapper::add_to_python_module(m);
- InferVStreamsWrapper::add_to_python_module(m);
-}
-
+void VStream_api_initialize_python_module(py::module &m);
} /* namespace hailort */
#endif // _VSTREAM_API_HPP_
-set(CMAKE_SYSTEM_NAME QNX)
-set(arch ntoaarch64)
-set(QNX_PROCESSOR aarch64)
+# CMake added fix for QCC compiler in this version - will not compile in older versions
+cmake_minimum_required(VERSION 3.14.0)
-set(CMAKE_C_COMPILER $ENV{QNX_HOST}/usr/bin/${arch}-gcc)
-set(CMAKE_C_COMPILER_TARGET ${arch})
+set(CMAKE_SYSTEM_NAME QNX)
+set(QNX_PROCESSOR aarch64le)
+SET(CMAKE_SYSTEM_PROCESSOR aarch64)
-set(CMAKE_CXX_COMPILER $ENV{QNX_HOST}/usr/bin/${arch}-g++)
-set(CMAKE_CXX_COMPILER_TARGET ${arch})
+SET(CMAKE_MAKE_PROGRAM "$ENV{QNX_HOST}/usr/bin/make" CACHE PATH "QNX Make Program")
+SET(CMAKE_SH "$ENV{QNX_HOST}/usr/bin/sh " CACHE PATH "QNX shell Program")
+SET(CMAKE_AR "$ENV{QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ar" CACHE PATH "QNX ar Program")
+SET(CMAKE_RANLIB "$ENV{QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ranlib" CACHE PATH "QNX ranlib Program")
+SET(CMAKE_NM "$ENV{QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-nm" CACHE PATH "QNX nm Program")
+SET(CMAKE_OBJCOPY "$ENV{QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-objcopy" CACHE PATH "QNX objcopy Program")
+SET(CMAKE_OBJDUMP "$ENV{QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-objdump" CACHE PATH "QNX objdump Program")
+SET(CMAKE_LINKER "$ENV{QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ld" CACHE PATH "QNX Linker Program")
+SET(CMAKE_STRIP "$ENV{QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-strip" CACHE PATH "QNX Strip Program")
add_definitions("-D_QNX_SOURCE")
-file(GLOB_RECURSE libgcc_a
- "$ENV{QNX_HOST}/usr/lib/gcc/${QNX_PROCESSOR}*/*/pic/libgcc.a")
+SET(CMAKE_SHARED_LIBRARY_PREFIX "lib")
+SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
+SET(CMAKE_STATIC_LIBRARY_PREFIX "lib")
+SET(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
+
+SET(CMAKE_C_COMPILER $ENV{QNX_HOST}/usr/bin/qcc)
+SET(CMAKE_C_FLAGS_DEBUG "-g")
+SET(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG")
+SET(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG")
+SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g")
+
+SET(CMAKE_CXX_COMPILER $ENV{QNX_HOST}/usr/bin/q++)
+SET(CMAKE_CXX_FLAGS_DEBUG "-g")
+SET(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
+SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
+SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
+
+LIST(APPEND CMAKE_FIND_ROOT_PATH $ENV{QNX_TARGET})
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+SET(CMAKE_C_FLAGS "-Vgcc_nto${QNX_PROCESSOR}" CACHE STRING "qcc c flags" FORCE)
+SET(CMAKE_CXX_FLAGS "-Vgcc_nto${QNX_PROCESSOR} -lang-c++ -Y_cxx" CACHE STRING "qcc cxx flags" FORCE)
-set(CMAKE_C_STANDARD_LIBRARIES_INIT
- "${libgcc_a} -lc -lsocket -Bstatic -lcS")
-set(CMAKE_CXX_STANDARD_LIBRARIES_INIT
- "-lc++ -lstdc++ -lm ${CMAKE_C_STANDARD_LIBRARIES_INIT}")
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--build-id=md5 -lang-c++ -lsocket ${EXTRA_CMAKE_LINKER_FLAGS}" CACHE STRING "exe_linker_flags")
+set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--build-id=md5 -lang-c++ -lsocket ${EXTRA_CMAKE_LINKER_FLAGS}" CACHE STRING "so_linker_flags")
# pybind is not supported in this platform
set(HAILO_BUILD_PYBIND 0)
+# CMake added fix for QCC compiler in this version - will not compile in older versions
+cmake_minimum_required(VERSION 3.14.0)
+
set(CMAKE_SYSTEM_NAME QNX)
-set(arch ntox86_64)
set(QNX_PROCESSOR x86_64)
+SET(CMAKE_SYSTEM_PROCESSOR x86_64)
-set(CMAKE_C_COMPILER $ENV{QNX_HOST}/usr/bin/${arch}-gcc)
-set(CMAKE_C_COMPILER_TARGET ${arch})
-
-set(CMAKE_CXX_COMPILER $ENV{QNX_HOST}/usr/bin/${arch}-g++)
-set(CMAKE_CXX_COMPILER_TARGET ${arch})
+SET(CMAKE_MAKE_PROGRAM "$ENV{QNX_HOST}/usr/bin/make" CACHE PATH "QNX Make Program")
+SET(CMAKE_SH "$ENV{QNX_HOST}/usr/bin/sh " CACHE PATH "QNX shell Program")
+SET(CMAKE_AR "$ENV{QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ar" CACHE PATH "QNX ar Program")
+SET(CMAKE_RANLIB "$ENV{QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ranlib" CACHE PATH "QNX ranlib Program")
+SET(CMAKE_NM "$ENV{QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-nm" CACHE PATH "QNX nm Program")
+SET(CMAKE_OBJCOPY "$ENV{QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-objcopy" CACHE PATH "QNX objcopy Program")
+SET(CMAKE_OBJDUMP "$ENV{QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-objdump" CACHE PATH "QNX objdump Program")
+SET(CMAKE_LINKER "$ENV{QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ld" CACHE PATH "QNX Linker Program")
+SET(CMAKE_STRIP "$ENV{QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-strip" CACHE PATH "QNX Strip Program")
add_definitions("-D_QNX_SOURCE")
-file(GLOB_RECURSE libgcc_a
- "$ENV{QNX_HOST}/usr/lib/gcc/${QNX_PROCESSOR}*/*/pic/libgcc.a")
+SET(CMAKE_SHARED_LIBRARY_PREFIX "lib")
+SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
+SET(CMAKE_STATIC_LIBRARY_PREFIX "lib")
+SET(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
+
+SET(CMAKE_C_COMPILER $ENV{QNX_HOST}/usr/bin/qcc)
+SET(CMAKE_C_FLAGS_DEBUG "-g")
+SET(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG")
+SET(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG")
+SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g")
+
+SET(CMAKE_CXX_COMPILER $ENV{QNX_HOST}/usr/bin/q++)
+SET(CMAKE_CXX_FLAGS_DEBUG "-g")
+SET(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
+SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
+SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
+
+LIST(APPEND CMAKE_FIND_ROOT_PATH $ENV{QNX_TARGET})
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+SET(CMAKE_C_FLAGS "-Vgcc_nto${QNX_PROCESSOR}" CACHE STRING "qcc c flags" FORCE)
+SET(CMAKE_CXX_FLAGS "-Vgcc_nto${QNX_PROCESSOR} -lang-c++ -Y_cxx" CACHE STRING "qcc cxx flags" FORCE)
-set(CMAKE_C_STANDARD_LIBRARIES_INIT
- "${libgcc_a} -lc -lsocket -Bstatic -lcS")
-set(CMAKE_CXX_STANDARD_LIBRARIES_INIT
- "-lc++ -lstdc++ -lm ${CMAKE_C_STANDARD_LIBRARIES_INIT}")
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--build-id=md5 -lang-c++ -lsocket ${EXTRA_CMAKE_LINKER_FLAGS}" CACHE STRING "exe_linker_flags")
+set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--build-id=md5 -lang-c++ -lsocket ${EXTRA_CMAKE_LINKER_FLAGS}" CACHE STRING "so_linker_flags")
# pybind is not supported in this platform
set(HAILO_BUILD_PYBIND 0)
- version: '3.8'
installation: deb
package_name: python3.8-dev
+ - version: '3.9'
+ installation: deb
+ package_name: python3.9-dev
- name: linux.aarch64
required_packages:
- gcc-aarch64-linux-gnu
installation: manual
package_name: https://launchpad.net/ubuntu/+source/python3.8/3.8.2-1ubuntu1/+build/18834117/+files/libpython3.8-dev_3.8.2-1ubuntu1_arm64.deb
package_dest: /usr/include/aarch64-linux-gnu
+ - version: '3.9'
+ installation: manual
+ package_name: https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa/+build/23779329/+files/libpython3.9-dev_3.9.13-1+bionic1_arm64.deb
+ package_dest: /usr/include/aarch64-linux-gnu
- name: linux.armv7l
required_packages:
- gcc-arm-linux-gnueabi
project(hailort-examples)
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake/")
-find_package(HailoRT)
find_package(Threads REQUIRED)
set(THREADS_PREFER_PTHREAD_FLAG ON)
+find_package(HailoRT 4.8.0 EXACT REQUIRED)
+
add_library(example_base INTERFACE)
target_link_libraries(example_base INTERFACE HailoRT::libhailort Threads::Threads)
add_subdirectory(cpp)
add_subdirectory(c)
+set_target_properties(${EXAMPLES_CPP_TARGETS} PROPERTIES CXX_STANDARD 14)
+
add_custom_target(hailort_examples DEPENDS ${EXAMPLES_C_TARGETS} ${EXAMPLES_CPP_TARGETS})
\ No newline at end of file
- Configure and activate network group and virtual streams.
- The data is sent to the device via input vstreams and received via output vstreams.
- The data is transformed before sent and after receiving in a different thread using the virtual stream pipeline.
- - `raw_streams_example` - Basic inference of a shortcut network using raw stream api.
- - The data is transformed before sent and after received in the same thread sending/receiving using the transformation api.
- - `data_quantization_example` - Demonstrates how to set input/output stream params so as to allow for custom quantization:
- - Input streams may be marked as quantized, so that input data will not to be automatically quantized by the HailoRT library.
- - Output streams may be marked as quantized, so that output data will remain quantized (as it is after exiting the device by default), and won't be 'de-quantized' by the HailoRT library.
- - This example uses pcie devices.
- - `switch_hefs_example` - Demonstrates how to work with multiple HEFs using virtual streams.
- - This example uses pcie devices.
- - `switch_single_io_hefs_example` - Demonstrates how to work with multiple single input single output HEFs using virtual streams.
- - This example uses pcie devices.
+ - `multi_device_example` - Basic inference of a shortcut network (inputs are sent through the device and right back out, without any changes made to the data), using VDevice over multiple pcie devices:
+ - Configure and activate network group and virtual streams.
+ - The data is sent to the device via input vstreams and received via output vstreams.
+ - The data is transformed before sent and after receiving in a different thread using the virtual stream pipeline.
- `multi_network_vstream_example` - Demonstrates how to work with multiple networks in a network group, using virtual streams.
- The example works with an HEF that contains one network group, and two networks in the network group.
- Configure the network group and set the batch size for each network.
- Get the networks information to create the vstreams for each network.
- The data is sent to the device via input vstreams and received via output vstreams.
- The data is transformed before sent and after receiving in a different thread using the virtual stream pipeline.
+ - `switch_network_groups_example` - Demonstrates how to work with multiple HEFs using virtual streams and HailoRT scheduler for automatic network group switching.
+ - This example uses pcie devices.
+ - `switch_single_io_network_groups_manually_example` - Demonstrates how to work with multiple single input single output HEFs, switching the created network groups manually, using virtual streams.
+ - `data_quantization_example` - Demonstrates how to set input/output stream params so as to allow for custom quantization:
+ - Input streams may be marked as quantized, so that input data will not to be automatically quantized by the HailoRT library.
+ - Output streams may be marked as quantized, so that output data will remain quantized (as it is after exiting the device by default), and won't be 'de-quantized' by the HailoRT library.
+ - This example uses pcie devices.
+ - `infer_pipeline_example` - Basic inference of a shortcut network using inference pipeline (blocking) api.
+ - this example uses udp device.
+ - `raw_streams_example` - Basic inference of a shortcut network using raw stream api.
+ - The data is transformed before sent and after received in the same thread sending/receiving using the transformation api.
+
- C++ examples:
- `vstreams_example` - Basic inference of a shortcut network, same as `vstreams_example` C example, uses HailoRT C++ api.
- - `raw_streams_example` - Basic inference of a shortcut network, same as `raw_streams_example` C example, uses HailoRT C++ api.
+ - `multi_device_example` - Basic inference of a shortcut network over multiple devices, same as `multi_device_example` C example, uses HailoRT C++ api.
- `multi_network_vstream_example` - Demonstrates how to work with multiple networks in a network group, same as `multi_network_vstream_example ` C example, uses HailoRT C++ api.
- - `switch_hefs_example` - Demonstrates how to work with multiple HEFs using virtual streams, same as `switch_hefs_example ` C example, uses HailoRT C++ api.
- - `switch_hefs_example_threads_reuse` - Same as `switch_hefs_example` CPP example, with performance optimizations for I/O threads re-usage instead of re-creation at each network group activation.
+ - `switch_network_groups_example` - Demonstrates how to work with multiple HEFs using virtual streams and HailoRT scheduler, same as `switch_network_groups_example ` C example, uses HailoRT C++ api.
+ - `switch_network_groups_manually_example` -Demonstrates how to work with multiple HEFs, switching the running network_groups manually, with performance optimizations for I/O threads re-usage instead of re-creation at each network group activation. Uses C++ api.
+ - `infer_streams_example` - Basic inference of a shortcut network, same as `raw_streams_example` C example, uses HailoRT C++ api.
+ - `infer_pipeline_example` - Basic inference of a shortcut network using inference pipeline (blocking) api.
+ - same as `infer_pipeline_example` C example, uses HailoRT C++ api.
+ - `raw_streams_example` - Basic inference of a shortcut network, same as `raw_streams_example` C example, uses HailoRT C++ api.
## Compiling with CMake
Examples are configured and compiled using the following commands:
add_executable(c_multi_network_vstream_example multi_network_vstream_example.c)
target_link_libraries(c_multi_network_vstream_example PRIVATE example_base)
-add_executable(c_switch_hefs_example switch_hefs_example.c)
-target_link_libraries(c_switch_hefs_example PRIVATE example_base)
+add_executable(c_switch_network_groups_example switch_network_groups_example.c)
+target_link_libraries(c_switch_network_groups_example PRIVATE example_base)
-add_executable(c_switch_single_io_hefs_example switch_single_io_hefs_example.c)
-target_link_libraries(c_switch_single_io_hefs_example PRIVATE example_base)
+add_executable(c_switch_single_io_network_groups_manually_example switch_single_io_network_groups_manually_example.c)
+target_link_libraries(c_switch_single_io_network_groups_manually_example PRIVATE example_base)
-add_executable(multi_device_example_c multi_device_example.c)
-target_link_libraries(multi_device_example_c PRIVATE example_base)
+add_executable(c_multi_device_example multi_device_example.c)
+target_link_libraries(c_multi_device_example PRIVATE example_base)
+
+add_executable(c_power_measurement_example power_measurement_example.c)
+target_link_libraries(c_power_measurement_example PRIVATE example_base)
set(EXAMPLES_C_TARGETS
c_data_quantization_example
c_vstreams_example
c_infer_pipeline_example
c_multi_network_vstream_example
- c_switch_hefs_example
- c_switch_single_io_hefs_example
- multi_device_example_c
+ c_switch_network_groups_example
+ c_switch_single_io_network_groups_manually_example
+ c_multi_device_example
+ c_power_measurement_example
PARENT_SCOPE)
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
**/
/**
- * @ file example_common.h
+ * @file example_common.h
* Common macros and defines used by Hailort Examples
**/
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
**/
/**
- * @ file data_quantization_example.c
+ * @file data_quantization_example.c
* This example demonstrates using quantization on an HEF network with multiple inputs and multiple outputs
**/
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
**/
/**
- * @ file hailo_thread.h
+ * @file hailo_thread.h
* Common threads related functions, for linux and windows
**/
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
**/
/**
- * @ file infer_pipeline_example.c
+ * @file infer_pipeline_example.c
* This example demonstrates the basic data-path on HailoRT using the high level API - Virtual Stream Pipeline.
* The program scans for Hailo-8 devices connected to a provided Ethernet interface, generates a random dataset,
* and runs it through the device with virtual streams pipeline.
* You shall not reproduce, modify or distribute this software without prior written permission.
**/
/**
- * @ file multi_device_example.c
+ * @file multi_device_example.c
* This example demonstrates how to work with multiple devices using virtual device.
* The program scans for Hailo-8 devices connected to a provided PCIe interface, generates random dataset,
* and runs it through the virtual device with virtual streams.
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file power_measurement_example.c
+ * This example demonstrates power and current measurements.
+ **/
+
+#include "common.h"
+#include "hailo/hailort.h"
+
+#include <string.h>
+
+#define SAMPLING_PERIOD (HAILO_SAMPLING_PERIOD_1100US)
+#define AVERAGE_FACTOR (HAILO_AVERAGE_FACTOR_256)
+#define DVM_OPTION (HAILO_DVM_OPTIONS_AUTO) // For current measurement over EVB - pass DVM explicitly (see hailo_dvm_options_t)
+#define MEASUREMENT_BUFFER_INDEX (HAILO_MEASUREMENT_BUFFER_INDEX_0)
+
+#define MEASUREMENTS_DURATION_SECS (5)
+#define MAX_PCIE_DEVICES (16)
+
+#define MEASUREMENT_UNITS(__type) \
+ ((HAILO_POWER_MEASUREMENT_TYPES__POWER == __type) ? ("W") : ("mA"))
+
+#define USAGE_ERROR_MSG ("Args parsing error.\nUsage: power_measurement_example [power / current]\n" \
+ "* power - measure power consumption in W\n" \
+ "* current - measure current in mA\n")
+
+#define POWER_ARG "power"
+#define CURRENT_ARG "current"
+
+
+void sleep_seconds(uint32_t duration_seconds)
+{
+#if defined(__unix__) || defined(__QNX__)
+ sleep(duration_seconds);
+#else
+ Sleep(duration_seconds);
+#endif
+}
+
+void parse_arguments(int argc, char **argv, hailo_power_measurement_types_t *measurement_type)
+{
+ if (2 != argc) {
+ printf(USAGE_ERROR_MSG);
+ exit(1);
+ }
+
+ if (0 == strncmp(POWER_ARG, argv[1], ARRAY_LENGTH(POWER_ARG))) {
+ *measurement_type = HAILO_POWER_MEASUREMENT_TYPES__POWER;
+ } else if (0 == strncmp(CURRENT_ARG, argv[1], ARRAY_LENGTH(CURRENT_ARG))) {
+ *measurement_type = HAILO_POWER_MEASUREMENT_TYPES__CURRENT;
+ } else {
+ printf(USAGE_ERROR_MSG);
+ exit(1);
+ }
+}
+
+hailo_status print_measurements_results(hailo_device device, hailo_power_measurement_data_t *result, hailo_power_measurement_types_t type)
+{
+ hailo_status status = HAILO_UNINITIALIZED;
+ hailo_device_id_t id = {0};
+ status = hailo_get_device_id(device, &id);
+ REQUIRE_SUCCESS(status, l_exit, "Failed to get device id");
+ const char* type_str = (type == HAILO_POWER_MEASUREMENT_TYPES__POWER) ? "Power measurement" :
+ "Current measurement";
+
+ printf("Device %s:\n", id.id);
+ printf(" %s\n", type_str);
+ printf(" Minimum value: %f %s\n", result->min_value, MEASUREMENT_UNITS(type));
+ printf(" Average value: %f %s\n", result->average_value, MEASUREMENT_UNITS(type));
+ printf(" Maximum value: %f %s\n", result->max_value, MEASUREMENT_UNITS(type));
+
+l_exit:
+ return status;
+}
+
+int main(int argc, char **argv)
+{
+ hailo_status status = HAILO_UNINITIALIZED;
+ hailo_vdevice vdevice = NULL;
+ hailo_pcie_device_info_t device_infos[MAX_PCIE_DEVICES];
+ size_t actual_device_count = 0;
+ hailo_vdevice_params_t params = {0};
+ hailo_device physical_devices[MAX_PCIE_DEVICES];
+ hailo_power_measurement_data_t measurement_result[MAX_PCIE_DEVICES] = {0};
+ hailo_power_measurement_types_t measurement_type = {0};
+
+ parse_arguments(argc, argv, &measurement_type);
+
+ status = hailo_scan_pcie_devices(device_infos, MAX_PCIE_DEVICES, &actual_device_count);
+ REQUIRE_SUCCESS(status, l_exit, "Failed to scan pcie_device");
+
+ status = hailo_init_vdevice_params(¶ms);
+ REQUIRE_SUCCESS(status, l_exit, "Failed to init vdevice_params");
+
+ params.device_count = (uint32_t)actual_device_count;
+ status = hailo_create_vdevice(¶ms, &vdevice);
+ REQUIRE_SUCCESS(status, l_exit, "Failed to create vdevice");
+
+ status = hailo_get_physical_devices(vdevice, physical_devices, &actual_device_count);
+ REQUIRE_SUCCESS(status, l_release_vdevice, "Failed to get physical devices");
+
+ for (size_t i = 0; i < actual_device_count; i++) {
+ status = hailo_stop_power_measurement(physical_devices[i]);
+ REQUIRE_SUCCESS(status, l_exit, "Failed stopping former measurements");
+
+ status = hailo_set_power_measurement(physical_devices[i], MEASUREMENT_BUFFER_INDEX, DVM_OPTION, measurement_type);
+ REQUIRE_SUCCESS(status, l_exit, "Failed setting measurement params");
+
+ status = hailo_start_power_measurement(physical_devices[i], AVERAGE_FACTOR, SAMPLING_PERIOD);
+ REQUIRE_SUCCESS(status, l_exit, "Failed to start measurement");
+ }
+
+ sleep_seconds(MEASUREMENTS_DURATION_SECS);
+
+ for (size_t i = 0; i < actual_device_count; i++) {
+ status = hailo_stop_power_measurement(physical_devices[i]);
+ REQUIRE_SUCCESS(status, l_exit, "Failed to stop measurement");
+
+ status = hailo_get_power_measurement(physical_devices[i], MEASUREMENT_BUFFER_INDEX, true, &(measurement_result[i]));
+ REQUIRE_SUCCESS(status, l_exit, "Failed to get measurement results");
+
+ status = print_measurements_results(physical_devices[i], &(measurement_result[i]), measurement_type);
+ REQUIRE_SUCCESS(status, l_release_vdevice, "Failed to print measurement results");
+ }
+
+ status = HAILO_SUCCESS;
+
+l_release_vdevice:
+ (void) hailo_release_vdevice(vdevice);
+l_exit:
+ return status;
+}
\ No newline at end of file
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
**/
/**
- * @ file raw_streams_example.c
+ * @file raw_streams_example.c
* This example demonstrates basic usage of HailoRT streaming api.
* It loads an HEF network with multiple inputs and multiple outputs into a Hailo PCIe device and performs a
* short inference.
size_t index = 0;
status = hailo_create_pcie_device(NULL, &device);
+ /*
+ For simplicity, passing NULL as `device_info` - This function will fail in case more than one PCIe device is present.
+ See `hailo_scan_pcie_devices` and `hailo_create_pcie_device` functions documentation.
+ */
REQUIRE_SUCCESS(status, l_exit, "Failed to create pcie_device");
+
status = hailo_create_hef_file(&hef, HEF_FILE);
REQUIRE_SUCCESS(status, l_release_device, "Failed creating hef file %s", HEF_FILE);
+++ /dev/null
-/**
- * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
- * Distributed under the MIT license (https://opensource.org/licenses/MIT)
- **/
-/**
- * @ file switch_hefs_example.c
- * This example demonstrates basic usage of HailoRT streaming api over multiple network groups, using vstreams.
- * It loads several HEF networks with single/multiple inputs and single/multiple outputs into a Hailo PCIe VDevice and performs a
- * short inference on each one.
- * After inference is finished, the example switches to the next HEF and start inference again.
- **/
-
-#include "common.h"
-#include "hailo_thread.h"
-#include "hailo/hailort.h"
-#include <time.h>
-
-#define MAX_HEF_PATH_LEN (255)
-#define MAX_EDGE_LAYERS (16)
-
-#define INFER_FRAME_COUNT (100)
-#define HEF_COUNT (2)
-#define RUN_COUNT (10)
-#define DEVICE_COUNT (1)
-
-typedef struct write_thread_args_t {
- hailo_input_vstream input_vstream;
- uint8_t *src_data;
- size_t src_frame_size;
-} write_thread_args_t;
-
-typedef struct read_thread_args_t {
- hailo_output_vstream output_vstream;
- uint8_t *dst_data;
- size_t dst_frame_size;
-} read_thread_args_t;
-
-thread_return_type write_to_device(void *args)
-{
- hailo_status status = HAILO_UNINITIALIZED;
- write_thread_args_t *write_args = (write_thread_args_t*)args;
-
- for (uint32_t frame = 0; frame < INFER_FRAME_COUNT; frame++) {
- // Write data
- status = hailo_vstream_write_raw_buffer(write_args->input_vstream, write_args->src_data, write_args->src_frame_size);
- REQUIRE_SUCCESS(status, l_exit, "Failed writing input frame to device");
- }
-
- status = HAILO_SUCCESS;
-l_exit:
- return (thread_return_type)status;
-}
-
-thread_return_type read_from_device(void *args)
-{
- hailo_status status = HAILO_UNINITIALIZED;
- read_thread_args_t *read_args = (read_thread_args_t*)args;
-
- for (uint32_t i = 0; i < INFER_FRAME_COUNT; i++) {
- // Read data
- status = hailo_vstream_read_raw_buffer(read_args->output_vstream, read_args->dst_data, read_args->dst_frame_size);
- REQUIRE_SUCCESS(status, l_exit, "Failed reading output frame from device");
-
- // Process data here
- }
-
- status = HAILO_SUCCESS;
-l_exit:
- return (thread_return_type)status;
-}
-
-hailo_status create_input_vstream_thread(hailo_input_vstream input_vstream, uint8_t *src_data, size_t src_frame_size,
- hailo_thread *input_thread, write_thread_args_t *write_args)
-{
- write_args->src_data = src_data;
- write_args->src_frame_size = src_frame_size;
- write_args->input_vstream = input_vstream;
-
- // Run write
- return hailo_create_thread(write_to_device, write_args, input_thread);
-}
-
-hailo_status create_output_vstream_thread(hailo_output_vstream output_vstream, uint8_t *dst_data, size_t dst_frame_size,
- hailo_thread *output_thread, read_thread_args_t *read_args)
-{
- read_args->dst_data = dst_data;
- read_args->dst_frame_size = dst_frame_size;
- read_args->output_vstream = output_vstream;
-
- // Run read
- return hailo_create_thread(read_from_device, read_args, output_thread);
-}
-
-hailo_status build_vstreams(hailo_configured_network_group network_group,
- hailo_input_vstream *input_vstreams, size_t *input_frame_sizes, uint8_t **src_data,
- hailo_output_vstream *output_vstreams, size_t *output_frame_sizes, uint8_t **dst_data,
- size_t *num_input_vstreams, size_t *num_output_vstreams)
-{
- hailo_status status = HAILO_UNINITIALIZED;
- hailo_input_vstream_params_by_name_t input_vstream_params[MAX_EDGE_LAYERS];
- hailo_output_vstream_params_by_name_t output_vstream_params[MAX_EDGE_LAYERS];
-
- // Make sure it can hold amount of vstreams for hailo_make_input/output_vstream_params
- size_t input_vstream_size = MAX_EDGE_LAYERS;
- size_t output_vstream_size = MAX_EDGE_LAYERS;
-
- status = hailo_make_input_vstream_params(network_group, true, HAILO_FORMAT_TYPE_AUTO,
- input_vstream_params, &input_vstream_size);
- REQUIRE_SUCCESS(status, l_exit, "Failed making input virtual stream params");
- *num_input_vstreams = input_vstream_size;
-
- status = hailo_make_output_vstream_params(network_group, true, HAILO_FORMAT_TYPE_AUTO,
- output_vstream_params, &output_vstream_size);
- REQUIRE_SUCCESS(status, l_exit, "Failed making output virtual stream params");
- *num_output_vstreams = output_vstream_size;
-
- REQUIRE_ACTION((*num_input_vstreams <= MAX_EDGE_LAYERS || *num_output_vstreams <= MAX_EDGE_LAYERS),
- status = HAILO_INVALID_OPERATION, l_exit, "Trying to infer network with too many input/output virtual streams, "
- "Maximum amount is %d, (either change HEF or change the definition of MAX_EDGE_LAYERS)\n", MAX_EDGE_LAYERS);
-
- status = hailo_create_input_vstreams(network_group, input_vstream_params, input_vstream_size, input_vstreams);
- REQUIRE_SUCCESS(status, l_exit, "Failed creating virtual stream");
-
- status = hailo_create_output_vstreams(network_group, output_vstream_params, output_vstream_size, output_vstreams);
- REQUIRE_SUCCESS(status, l_release_input_vstream, "Failed creating virtual stream");
-
- for (size_t i = 0; i < input_vstream_size; i++) {
- status = hailo_get_input_vstream_frame_size(input_vstreams[i], &input_frame_sizes[i]);
- REQUIRE_SUCCESS(status, l_clear_buffers, "Failed getting input virtual stream frame size");
-
- src_data[i] = (uint8_t*)malloc(input_frame_sizes[i]);
- REQUIRE_ACTION(NULL != src_data[i], status = HAILO_OUT_OF_HOST_MEMORY, l_clear_buffers, "Out of memory");
-
- // Prepare data here
- for (size_t frame_index = 0; frame_index < input_frame_sizes[i]; frame_index++) {
- src_data[i][frame_index] = (uint8_t)(rand() % 256);
- }
- }
-
- for (size_t i = 0; i < output_vstream_size; i++) {
- status = hailo_get_output_vstream_frame_size(output_vstreams[i], &output_frame_sizes[i]);
- REQUIRE_SUCCESS(status, l_clear_buffers, "Failed getting input virtual stream frame size");
-
- dst_data[i] = (uint8_t*)malloc(output_frame_sizes[i]);
- REQUIRE_ACTION(NULL != dst_data[i], status = HAILO_OUT_OF_HOST_MEMORY, l_clear_buffers, "Out of memory");
- }
-
- status = HAILO_SUCCESS;
- goto l_exit;
-
-l_clear_buffers:
- for (size_t i = 0; i < input_vstream_size; i++) {
- FREE(src_data[i]);
- }
- for (size_t i = 0; i < output_vstream_size; i++) {
- FREE(dst_data[i]);
- }
-
- (void)hailo_release_output_vstreams(output_vstreams, output_vstream_size);
-l_release_input_vstream:
- (void)hailo_release_input_vstreams(input_vstreams, input_vstream_size);
-l_exit:
- return status;
-}
-
-int main()
-{
- hailo_status status = HAILO_UNINITIALIZED;
- hailo_vdevice vdevice = NULL;
- hailo_vdevice_params_t params = {0};
- hailo_hef hef[HEF_COUNT] = {NULL};
- hailo_configure_params_t configure_params = {0};
- hailo_configured_network_group network_groups[HEF_COUNT] = {NULL};
- size_t network_groups_size = 1;
- hailo_activated_network_group activated_network_group = NULL;
- hailo_input_vstream input_vstreams[HEF_COUNT][MAX_EDGE_LAYERS];
- hailo_output_vstream output_vstreams[HEF_COUNT][MAX_EDGE_LAYERS];
- size_t input_frame_size[HEF_COUNT][MAX_EDGE_LAYERS];
- size_t output_frame_size[HEF_COUNT][MAX_EDGE_LAYERS];
- // Initialize 2d array to all NULL
- uint8_t *src_data[HEF_COUNT][MAX_EDGE_LAYERS];
- uint8_t *dst_data[HEF_COUNT][MAX_EDGE_LAYERS];
- size_t num_input_vstreams[HEF_COUNT];
- size_t num_output_vstreams[HEF_COUNT];
- uint8_t hef_index = 0;
- uint8_t run_index = 0;
-
- hailo_thread input_vstream_threads[MAX_EDGE_LAYERS];
- hailo_thread output_vstream_threads[MAX_EDGE_LAYERS];
- write_thread_args_t write_args[MAX_EDGE_LAYERS];
- read_thread_args_t read_args[MAX_EDGE_LAYERS];
-
- bool break_main_loop = false;
-
- char HEF_FILES[HEF_COUNT][MAX_HEF_PATH_LEN] = {"hefs/shortcut_net.hef", "hefs/shortcut_net.hef"};
-
- status = hailo_init_vdevice_params(¶ms);
- REQUIRE_SUCCESS(status, l_exit, "Failed init vdevice_params");
-
- params.device_count = DEVICE_COUNT;
- status = hailo_create_vdevice(¶ms, &vdevice);
- REQUIRE_SUCCESS(status, l_exit, "Failed to create vdevice");
-
- for (hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
- /* Select user HEFs here. In this example it's the same HEF for all networks */
- status = hailo_create_hef_file(&hef[hef_index], HEF_FILES[hef_index]);
- REQUIRE_SUCCESS(status, l_release_hef, "Failed creating hef file %s", HEF_FILES[hef_index]);
-
- status = hailo_init_configure_params(hef[hef_index], HAILO_STREAM_INTERFACE_PCIE, &configure_params);
- REQUIRE_SUCCESS(status, l_release_hef, "Failed init configure params");
-
- status = hailo_configure_vdevice(vdevice, hef[hef_index], &configure_params, &network_groups[hef_index], &network_groups_size);
- REQUIRE_SUCCESS(status, l_release_hef, "Failed configuring vdevcie");
- REQUIRE_ACTION(network_groups_size == 1, status = HAILO_INVALID_ARGUMENT, l_release_hef,
- "Unexpected network group size");
-
- status = build_vstreams(network_groups[hef_index],
- input_vstreams[hef_index], input_frame_size[hef_index], src_data[hef_index],
- output_vstreams[hef_index], output_frame_size[hef_index], dst_data[hef_index],
- &num_input_vstreams[hef_index], &num_output_vstreams[hef_index]);
- REQUIRE_SUCCESS(status, l_release_vstreams, "Failed building streams");
- }
-
- // Inference part
- for (run_index = 0; run_index < RUN_COUNT; run_index++) {
- for (hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
- status = hailo_activate_network_group(network_groups[hef_index], NULL, &activated_network_group);
- REQUIRE_SUCCESS(status, l_release_vstreams, "Failed activate network group");
-
- for (size_t i = 0; i < num_input_vstreams[hef_index]; i++) {
- status = create_input_vstream_thread(input_vstreams[hef_index][i], src_data[hef_index][i],
- input_frame_size[hef_index][i], &input_vstream_threads[i], &write_args[i]);
- }
-
- for (size_t i = 0; i < num_output_vstreams[hef_index]; i++) {
- status = create_output_vstream_thread(output_vstreams[hef_index][i], dst_data[hef_index][i],
- output_frame_size[hef_index][i], &output_vstream_threads[i], &read_args[i]);
- }
-
- for (size_t i = 0; i < num_input_vstreams[hef_index]; i++) {
- status = hailo_join_thread(&input_vstream_threads[i]);
- if (HAILO_SUCCESS != status) {
- printf("write_thread failed \n");
- break_main_loop = true;
- }
- }
-
- for (size_t i = 0; i < num_output_vstreams[hef_index]; i++) {
- status = hailo_join_thread(&output_vstream_threads[i]);
- if (HAILO_SUCCESS != status) {
- printf("write_thread failed \n");
- break_main_loop = true;
- }
- }
-
- status = hailo_deactivate_network_group(activated_network_group);
- REQUIRE_SUCCESS(status, l_deactivate_network_group, "Failed to de-activate network group");
-
- if(break_main_loop) {
- goto l_release_vstreams;
- }
- }
- }
-
- printf("Inference ran successfully\n");
- status = HAILO_SUCCESS;
- goto l_release_vstreams;
-
-l_deactivate_network_group:
- (void)hailo_deactivate_network_group(activated_network_group);
-l_release_vstreams:
- for (hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
- (void)hailo_release_output_vstreams(output_vstreams[hef_index], num_output_vstreams[hef_index]);
- (void)hailo_release_input_vstreams(input_vstreams[hef_index], num_input_vstreams[hef_index]);
- }
-
- for (hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
- for (size_t i = 0; i < num_input_vstreams[hef_index]; i++) {
- if (NULL != src_data[hef_index] && NULL != src_data[hef_index][i]) {
- FREE(src_data[hef_index][i]);
- }
- }
- for (size_t i = 0; i < num_output_vstreams[hef_index]; i++) {
- if (NULL != dst_data[hef_index] && NULL != dst_data[hef_index][i]) {
- FREE(dst_data[hef_index][i]);
- }
- }
- }
-l_release_hef:
- for (hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
- if (NULL != hef[hef_index]) {
- (void)hailo_release_hef(hef[hef_index]);
- }
- }
- (void)hailo_release_vdevice(vdevice);
-l_exit:
- return status;
-}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file switch_network_groups_example.c
+ * This example demonstrates basic usage of HailoRT streaming api over multiple network groups, using VStreams.
+ * It loads several network_groups (via several HEFs) into a Hailo PCIe VDevice and performs a inferences on all of them in parallel.
+ * The network_groups switching is performed automatically by the HailoRT scheduler.
+ **/
+
+#include "common.h"
+#include "hailo_thread.h"
+#include "hailo/hailort.h"
+#include <time.h>
+
+#define MAX_HEF_PATH_LEN (255)
+#define MAX_EDGE_LAYERS (16)
+
+#define INFER_FRAME_COUNT (100)
+#define HEF_COUNT (2)
+#define DEVICE_COUNT (1)
+
+typedef struct write_thread_args_t {
+ hailo_input_vstream input_vstream;
+ uint8_t *src_data;
+ size_t src_frame_size;
+} write_thread_args_t;
+
+typedef struct read_thread_args_t {
+ hailo_output_vstream output_vstream;
+ uint8_t *dst_data;
+ size_t dst_frame_size;
+} read_thread_args_t;
+
+thread_return_type write_to_device(void *args)
+{
+ hailo_status status = HAILO_UNINITIALIZED;
+ write_thread_args_t *write_args = (write_thread_args_t*)args;
+
+ for (uint32_t frame = 0; frame < INFER_FRAME_COUNT; frame++) {
+ // Write data
+ status = hailo_vstream_write_raw_buffer(write_args->input_vstream, write_args->src_data, write_args->src_frame_size);
+ REQUIRE_SUCCESS(status, l_exit, "Failed writing input frame to device");
+ }
+
+ status = HAILO_SUCCESS;
+l_exit:
+ return (thread_return_type)status;
+}
+
+thread_return_type read_from_device(void *args)
+{
+ hailo_status status = HAILO_UNINITIALIZED;
+ read_thread_args_t *read_args = (read_thread_args_t*)args;
+
+ for (uint32_t i = 0; i < INFER_FRAME_COUNT; i++) {
+ // Read data
+ status = hailo_vstream_read_raw_buffer(read_args->output_vstream, read_args->dst_data, read_args->dst_frame_size);
+ REQUIRE_SUCCESS(status, l_exit, "Failed reading output frame from device");
+
+ // Process data here
+ }
+
+ status = HAILO_SUCCESS;
+l_exit:
+ return (thread_return_type)status;
+}
+
+hailo_status create_input_vstream_thread(hailo_input_vstream input_vstream, uint8_t *src_data, size_t src_frame_size,
+ hailo_thread *input_thread, write_thread_args_t *write_args)
+{
+ write_args->src_data = src_data;
+ write_args->src_frame_size = src_frame_size;
+ write_args->input_vstream = input_vstream;
+
+ // Run write
+ return hailo_create_thread(write_to_device, write_args, input_thread);
+}
+
+hailo_status create_output_vstream_thread(hailo_output_vstream output_vstream, uint8_t *dst_data, size_t dst_frame_size,
+ hailo_thread *output_thread, read_thread_args_t *read_args)
+{
+ read_args->dst_data = dst_data;
+ read_args->dst_frame_size = dst_frame_size;
+ read_args->output_vstream = output_vstream;
+
+ // Run read
+ return hailo_create_thread(read_from_device, read_args, output_thread);
+}
+
+hailo_status build_vstreams(hailo_configured_network_group network_group,
+ hailo_input_vstream *input_vstreams, size_t *input_frame_sizes, uint8_t **src_data,
+ hailo_output_vstream *output_vstreams, size_t *output_frame_sizes, uint8_t **dst_data,
+ size_t *num_input_vstreams, size_t *num_output_vstreams)
+{
+ hailo_status status = HAILO_UNINITIALIZED;
+ hailo_input_vstream_params_by_name_t input_vstream_params[MAX_EDGE_LAYERS];
+ hailo_output_vstream_params_by_name_t output_vstream_params[MAX_EDGE_LAYERS];
+
+ // Make sure it can hold amount of vstreams for hailo_make_input/output_vstream_params
+ size_t input_vstream_size = MAX_EDGE_LAYERS;
+ size_t output_vstream_size = MAX_EDGE_LAYERS;
+
+ status = hailo_make_input_vstream_params(network_group, true, HAILO_FORMAT_TYPE_AUTO,
+ input_vstream_params, &input_vstream_size);
+ REQUIRE_SUCCESS(status, l_exit, "Failed making input virtual stream params");
+ *num_input_vstreams = input_vstream_size;
+
+ status = hailo_make_output_vstream_params(network_group, true, HAILO_FORMAT_TYPE_AUTO,
+ output_vstream_params, &output_vstream_size);
+ REQUIRE_SUCCESS(status, l_exit, "Failed making output virtual stream params");
+ *num_output_vstreams = output_vstream_size;
+
+ REQUIRE_ACTION((*num_input_vstreams <= MAX_EDGE_LAYERS || *num_output_vstreams <= MAX_EDGE_LAYERS),
+ status = HAILO_INVALID_OPERATION, l_exit, "Trying to infer network with too many input/output virtual streams, "
+ "Maximum amount is %d, (either change HEF or change the definition of MAX_EDGE_LAYERS)\n", MAX_EDGE_LAYERS);
+
+ status = hailo_create_input_vstreams(network_group, input_vstream_params, input_vstream_size, input_vstreams);
+ REQUIRE_SUCCESS(status, l_exit, "Failed creating virtual stream");
+
+ status = hailo_create_output_vstreams(network_group, output_vstream_params, output_vstream_size, output_vstreams);
+ REQUIRE_SUCCESS(status, l_release_input_vstream, "Failed creating virtual stream");
+
+ for (size_t i = 0; i < input_vstream_size; i++) {
+ status = hailo_get_input_vstream_frame_size(input_vstreams[i], &input_frame_sizes[i]);
+ REQUIRE_SUCCESS(status, l_clear_buffers, "Failed getting input virtual stream frame size");
+
+ src_data[i] = (uint8_t*)malloc(input_frame_sizes[i]);
+ REQUIRE_ACTION(NULL != src_data[i], status = HAILO_OUT_OF_HOST_MEMORY, l_clear_buffers, "Out of memory");
+
+ // Prepare data here
+ for (size_t frame_index = 0; frame_index < input_frame_sizes[i]; frame_index++) {
+ src_data[i][frame_index] = (uint8_t)(rand() % 256);
+ }
+ }
+
+ for (size_t i = 0; i < output_vstream_size; i++) {
+ status = hailo_get_output_vstream_frame_size(output_vstreams[i], &output_frame_sizes[i]);
+ REQUIRE_SUCCESS(status, l_clear_buffers, "Failed getting input virtual stream frame size");
+
+ dst_data[i] = (uint8_t*)malloc(output_frame_sizes[i]);
+ REQUIRE_ACTION(NULL != dst_data[i], status = HAILO_OUT_OF_HOST_MEMORY, l_clear_buffers, "Out of memory");
+ }
+
+ status = HAILO_SUCCESS;
+ goto l_exit;
+
+l_clear_buffers:
+ for (size_t i = 0; i < input_vstream_size; i++) {
+ FREE(src_data[i]);
+ }
+ for (size_t i = 0; i < output_vstream_size; i++) {
+ FREE(dst_data[i]);
+ }
+
+ (void)hailo_release_output_vstreams(output_vstreams, output_vstream_size);
+l_release_input_vstream:
+ (void)hailo_release_input_vstreams(input_vstreams, input_vstream_size);
+l_exit:
+ return status;
+}
+
+int main()
+{
+ hailo_status status = HAILO_UNINITIALIZED;
+ hailo_vdevice vdevice = NULL;
+ hailo_vdevice_params_t params = {0};
+ hailo_hef hef[HEF_COUNT] = {NULL};
+ hailo_configure_params_t configure_params = {0};
+ hailo_configured_network_group network_groups[HEF_COUNT] = {NULL};
+ size_t network_groups_size = 1;
+ hailo_input_vstream input_vstreams[HEF_COUNT][MAX_EDGE_LAYERS];
+ hailo_output_vstream output_vstreams[HEF_COUNT][MAX_EDGE_LAYERS];
+ size_t input_frame_size[HEF_COUNT][MAX_EDGE_LAYERS];
+ size_t output_frame_size[HEF_COUNT][MAX_EDGE_LAYERS];
+ // Initialize 2d array to all NULL
+ uint8_t *src_data[HEF_COUNT][MAX_EDGE_LAYERS];
+ uint8_t *dst_data[HEF_COUNT][MAX_EDGE_LAYERS];
+ size_t num_input_vstreams[HEF_COUNT];
+ size_t num_output_vstreams[HEF_COUNT];
+ uint8_t hef_index = 0;
+
+ hailo_thread input_vstream_threads[HEF_COUNT][MAX_EDGE_LAYERS];
+ hailo_thread output_vstream_threads[HEF_COUNT][MAX_EDGE_LAYERS];
+ write_thread_args_t write_args[HEF_COUNT][MAX_EDGE_LAYERS];
+ read_thread_args_t read_args[HEF_COUNT][MAX_EDGE_LAYERS];
+
+ char HEF_FILES[HEF_COUNT][MAX_HEF_PATH_LEN] = {"hefs/multi_network_shortcut_net.hef", "hefs/shortcut_net.hef"};
+
+ status = hailo_init_vdevice_params(¶ms);
+ REQUIRE_SUCCESS(status, l_exit, "Failed init vdevice_params");
+
+ params.device_count = DEVICE_COUNT;
+ params.scheduling_algorithm = HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN;
+ status = hailo_create_vdevice(¶ms, &vdevice);
+ REQUIRE_SUCCESS(status, l_exit, "Failed to create vdevice");
+
+ for (hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
+ /* Select user HEFs here. In this example it's the same HEF for all networks */
+ status = hailo_create_hef_file(&hef[hef_index], HEF_FILES[hef_index]);
+ REQUIRE_SUCCESS(status, l_release_hef, "Failed creating hef file %s", HEF_FILES[hef_index]);
+
+ status = hailo_init_configure_params(hef[hef_index], HAILO_STREAM_INTERFACE_PCIE, &configure_params);
+ REQUIRE_SUCCESS(status, l_release_hef, "Failed init configure params");
+
+ status = hailo_configure_vdevice(vdevice, hef[hef_index], &configure_params, &network_groups[hef_index], &network_groups_size);
+ REQUIRE_SUCCESS(status, l_release_hef, "Failed configuring vdevcie");
+ REQUIRE_ACTION(network_groups_size == 1, status = HAILO_INVALID_ARGUMENT, l_release_hef,
+ "Unexpected network group size");
+
+ status = build_vstreams(network_groups[hef_index],
+ input_vstreams[hef_index], input_frame_size[hef_index], src_data[hef_index],
+ output_vstreams[hef_index], output_frame_size[hef_index], dst_data[hef_index],
+ &num_input_vstreams[hef_index], &num_output_vstreams[hef_index]);
+ REQUIRE_SUCCESS(status, l_release_vstreams, "Failed building streams");
+ }
+
+ for (hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
+ for (size_t i = 0; i < num_input_vstreams[hef_index]; i++) {
+ status = create_input_vstream_thread(input_vstreams[hef_index][i], src_data[hef_index][i],
+ input_frame_size[hef_index][i], &input_vstream_threads[hef_index][i], &write_args[hef_index][i]);
+ }
+ REQUIRE_SUCCESS(status, l_release_vstreams, "Failed creating write threads");
+
+ for (size_t i = 0; i < num_output_vstreams[hef_index]; i++) {
+ status = create_output_vstream_thread(output_vstreams[hef_index][i], dst_data[hef_index][i],
+ output_frame_size[hef_index][i], &output_vstream_threads[hef_index][i], &read_args[hef_index][i]);
+ }
+ REQUIRE_SUCCESS(status, l_release_vstreams, "Failed creating read threads");
+ }
+
+ for (hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
+ for (size_t i = 0; i < num_input_vstreams[hef_index]; i++) {
+ status = hailo_join_thread(&input_vstream_threads[hef_index][i]);
+ if (HAILO_SUCCESS != status) {
+ printf("write_thread failed \n");
+ }
+ }
+
+ for (size_t i = 0; i < num_output_vstreams[hef_index]; i++) {
+ status = hailo_join_thread(&output_vstream_threads[hef_index][i]);
+ if (HAILO_SUCCESS != status) {
+ printf("read_thread failed \n");
+ }
+ }
+ }
+
+ printf("Inference ran successfully\n");
+ status = HAILO_SUCCESS;
+ goto l_release_vstreams;
+
+l_release_vstreams:
+ for (hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
+ (void)hailo_release_output_vstreams(output_vstreams[hef_index], num_output_vstreams[hef_index]);
+ (void)hailo_release_input_vstreams(input_vstreams[hef_index], num_input_vstreams[hef_index]);
+ }
+
+ for (hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
+ for (size_t i = 0; i < num_input_vstreams[hef_index]; i++) {
+ if (NULL != src_data[hef_index] && NULL != src_data[hef_index][i]) {
+ FREE(src_data[hef_index][i]);
+ }
+ }
+ for (size_t i = 0; i < num_output_vstreams[hef_index]; i++) {
+ if (NULL != dst_data[hef_index] && NULL != dst_data[hef_index][i]) {
+ FREE(dst_data[hef_index][i]);
+ }
+ }
+ }
+l_release_hef:
+ for (hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
+ if (NULL != hef[hef_index]) {
+ (void)hailo_release_hef(hef[hef_index]);
+ }
+ }
+ (void)hailo_release_vdevice(vdevice);
+l_exit:
+ return status;
+}
\ No newline at end of file
+++ /dev/null
-/**
- * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
- * Distributed under the MIT license (https://opensource.org/licenses/MIT)
- **/
-/**
- * @ file switch_single_io_hefs_example.c
- * This example demonstrates basic usage of HailoRT streaming api over multiple network groups, using vstreams.
- * It loads several HEF networks with a single input and a single output into a Hailo PCIe VDevice and performs a inference on each one.
- * After inference is finished, the example switches to the next HEF and start inference again.
- **/
-
-#include "common.h"
-#include "hailo_thread.h"
-#include "hailo/hailort.h"
-#include <time.h>
-
-#define MAX_HEF_PATH_LEN (255)
-#define MAX_EDGE_LAYERS (16)
-
-#define INFER_FRAME_COUNT (100)
-#define HEF_COUNT (2)
-#define RUN_COUNT (10)
-#define DEVICE_COUNT (1)
-
-typedef struct input_vstream_thread_args_t {
- hailo_configured_network_group *configured_networks;
- hailo_input_vstream_params_by_name_t *input_vstream_params;
-} input_vstream_thread_args_t;
-
-typedef struct output_vstream_thread_args_t {
- hailo_configured_network_group *configured_networks;
- hailo_activated_network_group *activated_network_group;
- hailo_output_vstream_params_by_name_t *output_vstream_params;
-} output_vstream_thread_args_t;
-
-thread_return_type input_vstream_thread_func(void *args)
-{
- hailo_status status = HAILO_UNINITIALIZED;
- hailo_input_vstream input_vstreams[HEF_COUNT];
- size_t input_frame_size[HEF_COUNT];
- uint8_t *src_data[HEF_COUNT];
- input_vstream_thread_args_t *input_vstream_args = (input_vstream_thread_args_t*)args;
-
- for (size_t hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
- // Input vstream size has to be one in this example- otherwise would haveve returned error
- status = hailo_create_input_vstreams(input_vstream_args->configured_networks[hef_index],
- &input_vstream_args->input_vstream_params[hef_index], 1, &input_vstreams[hef_index]);
- REQUIRE_SUCCESS(status, l_clear_src, "Failed creating virtual stream");
-
- status = hailo_get_input_vstream_frame_size(input_vstreams[hef_index], &input_frame_size[hef_index]);
- REQUIRE_SUCCESS(status, l_clear_src, "Failed getting input virtual stream frame size");
-
- src_data[hef_index] = (uint8_t*)malloc(input_frame_size[hef_index]);
- REQUIRE_ACTION(NULL != src_data[hef_index], status = HAILO_OUT_OF_HOST_MEMORY, l_clear_src, "Out of memory");
- }
-
- for (size_t run_index = 0; run_index < RUN_COUNT; run_index++) {
- for (size_t hef_index = 0 ; hef_index < HEF_COUNT; hef_index++) {
- // Wait for hef to be activated to send data
- hailo_wait_for_network_group_activation(input_vstream_args->configured_networks[hef_index], HAILO_INFINITE);
-
- // Send data on relevant Hef
- for (uint32_t frame = 0; frame < INFER_FRAME_COUNT; frame++) {
- // Prepare data here
- for (size_t i = 0; i < input_frame_size[hef_index]; i++) {
- src_data[hef_index][i] = (uint8_t)(rand() % 256);
- }
-
- status = hailo_vstream_write_raw_buffer(input_vstreams[hef_index], src_data[hef_index], input_frame_size[hef_index]);
- REQUIRE_SUCCESS(status, l_clear_src, "Failed writing input frame to device");
- }
- }
- }
-
- status = HAILO_SUCCESS;
-
-l_clear_src:
- for (size_t hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
- FREE(src_data[hef_index]);
- }
-
- (void)hailo_release_input_vstreams(input_vstreams, HEF_COUNT);
- return (thread_return_type)status;
-}
-
-thread_return_type output_vstream_thread_func(void *args)
-{
- hailo_status status = HAILO_UNINITIALIZED;
- hailo_output_vstream output_vstreams[HEF_COUNT];
- size_t output_frame_size[HEF_COUNT];
- uint8_t *dst_data[HEF_COUNT];
- output_vstream_thread_args_t *output_vstream_args = (output_vstream_thread_args_t*)args;
-
- for (size_t hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
- // Output vstream size has to be one in this example- otherwise would haveve returned error
- status = hailo_create_output_vstreams(output_vstream_args->configured_networks[hef_index],
- &output_vstream_args->output_vstream_params[hef_index], 1, &output_vstreams[hef_index]);
- REQUIRE_SUCCESS(status, l_clear_dst, "Failed creating virtual stream");
-
- status = hailo_get_output_vstream_frame_size(output_vstreams[hef_index], &output_frame_size[hef_index]);
- REQUIRE_SUCCESS(status, l_clear_dst, "Failed getting input virtual stream frame size");
-
- dst_data[hef_index] = (uint8_t*)malloc(output_frame_size[hef_index]);
- REQUIRE_ACTION(NULL != dst_data[hef_index], status = HAILO_OUT_OF_HOST_MEMORY, l_clear_dst, "Out of memory");
- }
-
- for (size_t run_index = 0; run_index < RUN_COUNT; run_index++) {
- for (size_t hef_index = 0 ; hef_index < HEF_COUNT; hef_index++) {
- // Wait for hef to be activated to send data
- hailo_wait_for_network_group_activation(output_vstream_args->configured_networks[hef_index], HAILO_INFINITE);
-
- for (uint32_t i = 0; i < INFER_FRAME_COUNT; i++) {
- // Read data
- status = hailo_vstream_read_raw_buffer(output_vstreams[hef_index],
- dst_data[hef_index], output_frame_size[hef_index]);
- REQUIRE_SUCCESS(status, l_deactivate_network_group, "Failed reading output frame from device");
-
- // Process data here
- }
-
- // Deavticate network after finishing inference
- status = hailo_deactivate_network_group(*(output_vstream_args->activated_network_group));
- REQUIRE_SUCCESS(status, l_deactivate_network_group, "Failed Deactivating network");
-
- // Dont activate on last iteration
- if (hef_index < HEF_COUNT - 1) {
- // Activate next network so input thread can start sending again
- status = hailo_activate_network_group(output_vstream_args->configured_networks[hef_index + 1],
- NULL, output_vstream_args->activated_network_group);
- REQUIRE_SUCCESS(status, l_clear_dst, "Failed Activating network");
- }
- else {
- // Meaning we finished a run and now need to activate the first network again for the next run
- if (run_index < RUN_COUNT - 1) {
- status = hailo_activate_network_group(output_vstream_args->configured_networks[0],
- NULL, output_vstream_args->activated_network_group);
- REQUIRE_SUCCESS(status, l_clear_dst, "Failed Activating network");
- }
- }
- }
- }
-
- status = HAILO_SUCCESS;
- goto l_clear_dst;
-
-l_deactivate_network_group:
- (void)hailo_deactivate_network_group(*(output_vstream_args->activated_network_group));
-l_clear_dst:
- for (size_t hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
- FREE(dst_data[hef_index]);
- }
-
- (void)hailo_release_output_vstreams(output_vstreams, HEF_COUNT);
- return (thread_return_type)status;
-}
-
-int main()
-{
- hailo_status status = HAILO_UNINITIALIZED;
- hailo_vdevice vdevice = NULL;
- hailo_vdevice_params_t params = {0};
- hailo_hef hef[HEF_COUNT] = {NULL};
- hailo_configure_params_t configure_params = {0};
- hailo_activated_network_group activated_network;
- hailo_configured_network_group network_groups[HEF_COUNT] = {NULL};
- size_t network_groups_size = 1;
- uint8_t hef_index = 0;
- hailo_input_vstream_params_by_name_t input_vstream_params[HEF_COUNT];
- hailo_output_vstream_params_by_name_t output_vstream_params[HEF_COUNT];
- size_t input_vstream_size = 1;
- size_t output_vstream_size = 1;
-
- hailo_thread input_vstream_thread = {0};
- hailo_thread output_vstream_thread = {0};
- input_vstream_thread_args_t input_args = {0};
- output_vstream_thread_args_t output_args = {0};
-
- char HEF_FILES[HEF_COUNT][250] = {"hefs/shortcut_net.hef","hefs/shortcut_net.hef"};
-
- status = hailo_init_vdevice_params(¶ms);
- REQUIRE_SUCCESS(status, l_exit, "Failed init vdevice_params");
-
- params.device_count = DEVICE_COUNT;
- status = hailo_create_vdevice(¶ms, &vdevice);
- REQUIRE_SUCCESS(status, l_exit, "Failed to create vdevice");
-
- for (hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
- /* Select user HEFs here. In this example it's the same HEF for all networks */
- status = hailo_create_hef_file(&hef[hef_index], HEF_FILES[hef_index]);
- REQUIRE_SUCCESS(status, l_release_hef, "Failed creating hef file %s", HEF_FILES[hef_index]);
-
- status = hailo_init_configure_params(hef[hef_index], HAILO_STREAM_INTERFACE_PCIE, &configure_params);
- REQUIRE_SUCCESS(status, l_release_hef, "Failed init configure params");
-
- status = hailo_configure_vdevice(vdevice, hef[hef_index], &configure_params, &network_groups[hef_index], &network_groups_size);
- REQUIRE_SUCCESS(status, l_release_hef, "Failed configuring vdevcie");
- REQUIRE_ACTION(network_groups_size == 1, status = HAILO_INVALID_ARGUMENT, l_release_hef,
- "Unexpected network group size");
-
- // Mae sure each hef is single input single output
- status = hailo_make_input_vstream_params(network_groups[hef_index], true, HAILO_FORMAT_TYPE_AUTO,
- &input_vstream_params[hef_index], &input_vstream_size);
- REQUIRE_SUCCESS(status, l_release_hef, "Failed making input virtual stream params");
- REQUIRE_ACTION(input_vstream_size == 1, status = HAILO_INVALID_ARGUMENT, l_release_hef,
- "INVALID HEF - Only hefs with single input vstream are allowed");
-
- status = hailo_make_output_vstream_params(network_groups[hef_index], true, HAILO_FORMAT_TYPE_AUTO,
- &output_vstream_params[hef_index], &output_vstream_size);
- REQUIRE_SUCCESS(status, l_release_hef, "Failed making output virtual stream params");
- REQUIRE_ACTION(output_vstream_size == 1, status = HAILO_INVALID_ARGUMENT, l_release_hef,
- "INVALID HEF - Only hefs with single output vstream are allowed");
- }
-
- input_args.configured_networks = network_groups;
- input_args.input_vstream_params = input_vstream_params;
-
- // Open input vstream and output vstream threads
- status = hailo_create_thread(input_vstream_thread_func, &input_args, &input_vstream_thread);
- REQUIRE_SUCCESS(status, l_release_hef, "Failed creating thread");
-
- output_args.configured_networks = network_groups;
- output_args.activated_network_group = &activated_network;
- output_args.output_vstream_params = output_vstream_params;
-
- // Open output vstream and output vstream threads
- status = hailo_create_thread(output_vstream_thread_func, &output_args, &output_vstream_thread);
- REQUIRE_SUCCESS(status, l_join_input_thread, "Failed creating thread");
-
- // Activate first network so input thread can start
- status = hailo_activate_network_group(network_groups[0], NULL, &activated_network);
- REQUIRE_SUCCESS(status, l_join_output_thread, "Failed Activating network");
-
-
- status = hailo_join_thread(&input_vstream_thread);
- REQUIRE_SUCCESS(status, l_join_output_thread, "Failed witing for input thread");
-
- status = hailo_join_thread(&output_vstream_thread);
- REQUIRE_SUCCESS(status, l_join_output_thread, "Failed witing for output thread");
-
- printf("Inference ran successfully\n");
- status = HAILO_SUCCESS;
- goto l_release_hef;
-
-l_join_output_thread:
- (void)hailo_join_thread(&output_vstream_thread);
-l_join_input_thread:
- (void)hailo_join_thread(&input_vstream_thread);
-l_release_hef:
- for (hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
- if (NULL != hef[hef_index]) {
- (void)hailo_release_hef(hef[hef_index]);
- }
- }
- (void)hailo_release_vdevice(vdevice);
-l_exit:
- return status;
-}
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file switch_single_io_network_groups_manually_example.c
+ * This example demonstrates basic usage of HailoRT streaming api over multiple network groups, using vstreams.
+ * It loads several HEF networks with a single input and a single output into a Hailo PCIe VDevice and performs a inference on each one.
+ * After inference is finished, the example switches to the next HEF and start inference again.
+ **/
+
+#include "common.h"
+#include "hailo_thread.h"
+#include "hailo/hailort.h"
+#include <time.h>
+
+#define MAX_HEF_PATH_LEN (255)
+#define MAX_EDGE_LAYERS (16)
+
+#define INFER_FRAME_COUNT (100)
+#define HEF_COUNT (2)
+#define RUN_COUNT (10)
+#define DEVICE_COUNT (1)
+
+typedef struct input_vstream_thread_args_t {
+ hailo_configured_network_group *configured_networks;
+ hailo_input_vstream_params_by_name_t *input_vstream_params;
+} input_vstream_thread_args_t;
+
+typedef struct output_vstream_thread_args_t {
+ hailo_configured_network_group *configured_networks;
+ hailo_activated_network_group *activated_network_group;
+ hailo_output_vstream_params_by_name_t *output_vstream_params;
+} output_vstream_thread_args_t;
+
+thread_return_type input_vstream_thread_func(void *args)
+{
+ hailo_status status = HAILO_UNINITIALIZED;
+ hailo_input_vstream input_vstreams[HEF_COUNT];
+ size_t input_frame_size[HEF_COUNT];
+ uint8_t *src_data[HEF_COUNT];
+ input_vstream_thread_args_t *input_vstream_args = (input_vstream_thread_args_t*)args;
+
+ for (size_t hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
+ // Input vstream size has to be one in this example- otherwise would haveve returned error
+ status = hailo_create_input_vstreams(input_vstream_args->configured_networks[hef_index],
+ &input_vstream_args->input_vstream_params[hef_index], 1, &input_vstreams[hef_index]);
+ REQUIRE_SUCCESS(status, l_clear_src, "Failed creating virtual stream");
+
+ status = hailo_get_input_vstream_frame_size(input_vstreams[hef_index], &input_frame_size[hef_index]);
+ REQUIRE_SUCCESS(status, l_clear_src, "Failed getting input virtual stream frame size");
+
+ src_data[hef_index] = (uint8_t*)malloc(input_frame_size[hef_index]);
+ REQUIRE_ACTION(NULL != src_data[hef_index], status = HAILO_OUT_OF_HOST_MEMORY, l_clear_src, "Out of memory");
+ }
+
+ for (size_t run_index = 0; run_index < RUN_COUNT; run_index++) {
+ for (size_t hef_index = 0 ; hef_index < HEF_COUNT; hef_index++) {
+ // Wait for hef to be activated to send data
+ hailo_wait_for_network_group_activation(input_vstream_args->configured_networks[hef_index], HAILO_INFINITE);
+
+ // Send data on relevant Hef
+ for (uint32_t frame = 0; frame < INFER_FRAME_COUNT; frame++) {
+ // Prepare data here
+ for (size_t i = 0; i < input_frame_size[hef_index]; i++) {
+ src_data[hef_index][i] = (uint8_t)(rand() % 256);
+ }
+
+ status = hailo_vstream_write_raw_buffer(input_vstreams[hef_index], src_data[hef_index], input_frame_size[hef_index]);
+ REQUIRE_SUCCESS(status, l_clear_src, "Failed writing input frame to device");
+ }
+ }
+ }
+
+ status = HAILO_SUCCESS;
+
+l_clear_src:
+ for (size_t hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
+ FREE(src_data[hef_index]);
+ }
+
+ (void)hailo_release_input_vstreams(input_vstreams, HEF_COUNT);
+ return (thread_return_type)status;
+}
+
+thread_return_type output_vstream_thread_func(void *args)
+{
+ hailo_status status = HAILO_UNINITIALIZED;
+ hailo_output_vstream output_vstreams[HEF_COUNT];
+ size_t output_frame_size[HEF_COUNT];
+ uint8_t *dst_data[HEF_COUNT];
+ output_vstream_thread_args_t *output_vstream_args = (output_vstream_thread_args_t*)args;
+
+ for (size_t hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
+ // Output vstream size has to be one in this example- otherwise would haveve returned error
+ status = hailo_create_output_vstreams(output_vstream_args->configured_networks[hef_index],
+ &output_vstream_args->output_vstream_params[hef_index], 1, &output_vstreams[hef_index]);
+ REQUIRE_SUCCESS(status, l_clear_dst, "Failed creating virtual stream");
+
+ status = hailo_get_output_vstream_frame_size(output_vstreams[hef_index], &output_frame_size[hef_index]);
+ REQUIRE_SUCCESS(status, l_clear_dst, "Failed getting input virtual stream frame size");
+
+ dst_data[hef_index] = (uint8_t*)malloc(output_frame_size[hef_index]);
+ REQUIRE_ACTION(NULL != dst_data[hef_index], status = HAILO_OUT_OF_HOST_MEMORY, l_clear_dst, "Out of memory");
+ }
+
+ for (size_t run_index = 0; run_index < RUN_COUNT; run_index++) {
+ for (size_t hef_index = 0 ; hef_index < HEF_COUNT; hef_index++) {
+ // Wait for hef to be activated to send data
+ hailo_wait_for_network_group_activation(output_vstream_args->configured_networks[hef_index], HAILO_INFINITE);
+
+ for (uint32_t i = 0; i < INFER_FRAME_COUNT; i++) {
+ // Read data
+ status = hailo_vstream_read_raw_buffer(output_vstreams[hef_index],
+ dst_data[hef_index], output_frame_size[hef_index]);
+ REQUIRE_SUCCESS(status, l_deactivate_network_group, "Failed reading output frame from device");
+
+ // Process data here
+ }
+
+ // Deavticate network after finishing inference
+ status = hailo_deactivate_network_group(*(output_vstream_args->activated_network_group));
+ REQUIRE_SUCCESS(status, l_deactivate_network_group, "Failed Deactivating network");
+
+ // Dont activate on last iteration
+ if (hef_index < HEF_COUNT - 1) {
+ // Activate next network so input thread can start sending again
+ status = hailo_activate_network_group(output_vstream_args->configured_networks[hef_index + 1],
+ NULL, output_vstream_args->activated_network_group);
+ REQUIRE_SUCCESS(status, l_clear_dst, "Failed Activating network");
+ }
+ else {
+ // Meaning we finished a run and now need to activate the first network again for the next run
+ if (run_index < RUN_COUNT - 1) {
+ status = hailo_activate_network_group(output_vstream_args->configured_networks[0],
+ NULL, output_vstream_args->activated_network_group);
+ REQUIRE_SUCCESS(status, l_clear_dst, "Failed Activating network");
+ }
+ }
+ }
+ }
+
+ status = HAILO_SUCCESS;
+ goto l_clear_dst;
+
+l_deactivate_network_group:
+ (void)hailo_deactivate_network_group(*(output_vstream_args->activated_network_group));
+l_clear_dst:
+ for (size_t hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
+ FREE(dst_data[hef_index]);
+ }
+
+ (void)hailo_release_output_vstreams(output_vstreams, HEF_COUNT);
+ return (thread_return_type)status;
+}
+
+int main()
+{
+ hailo_status status = HAILO_UNINITIALIZED;
+ hailo_vdevice vdevice = NULL;
+ hailo_vdevice_params_t params = {0};
+ hailo_hef hef[HEF_COUNT] = {NULL};
+ hailo_configure_params_t configure_params = {0};
+ hailo_activated_network_group activated_network;
+ hailo_configured_network_group network_groups[HEF_COUNT] = {NULL};
+ size_t network_groups_size = 1;
+ uint8_t hef_index = 0;
+ hailo_input_vstream_params_by_name_t input_vstream_params[HEF_COUNT];
+ hailo_output_vstream_params_by_name_t output_vstream_params[HEF_COUNT];
+ size_t input_vstream_size = 1;
+ size_t output_vstream_size = 1;
+
+ hailo_thread input_vstream_thread = {0};
+ hailo_thread output_vstream_thread = {0};
+ input_vstream_thread_args_t input_args = {0};
+ output_vstream_thread_args_t output_args = {0};
+
+ char HEF_FILES[HEF_COUNT][250] = {"hefs/shortcut_net.hef","hefs/shortcut_net.hef"};
+
+ status = hailo_init_vdevice_params(¶ms);
+ REQUIRE_SUCCESS(status, l_exit, "Failed init vdevice_params");
+
+ params.device_count = DEVICE_COUNT;
+ status = hailo_create_vdevice(¶ms, &vdevice);
+ REQUIRE_SUCCESS(status, l_exit, "Failed to create vdevice");
+
+ for (hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
+ /* Select user HEFs here. In this example it's the same HEF for all networks */
+ status = hailo_create_hef_file(&hef[hef_index], HEF_FILES[hef_index]);
+ REQUIRE_SUCCESS(status, l_release_hef, "Failed creating hef file %s", HEF_FILES[hef_index]);
+
+ status = hailo_init_configure_params(hef[hef_index], HAILO_STREAM_INTERFACE_PCIE, &configure_params);
+ REQUIRE_SUCCESS(status, l_release_hef, "Failed init configure params");
+
+ status = hailo_configure_vdevice(vdevice, hef[hef_index], &configure_params, &network_groups[hef_index], &network_groups_size);
+ REQUIRE_SUCCESS(status, l_release_hef, "Failed configuring vdevcie");
+ REQUIRE_ACTION(network_groups_size == 1, status = HAILO_INVALID_ARGUMENT, l_release_hef,
+ "Unexpected network group size");
+
+ // Mae sure each hef is single input single output
+ status = hailo_make_input_vstream_params(network_groups[hef_index], true, HAILO_FORMAT_TYPE_AUTO,
+ &input_vstream_params[hef_index], &input_vstream_size);
+ REQUIRE_SUCCESS(status, l_release_hef, "Failed making input virtual stream params");
+ REQUIRE_ACTION(input_vstream_size == 1, status = HAILO_INVALID_ARGUMENT, l_release_hef,
+ "INVALID HEF - Only hefs with single input vstream are allowed");
+
+ status = hailo_make_output_vstream_params(network_groups[hef_index], true, HAILO_FORMAT_TYPE_AUTO,
+ &output_vstream_params[hef_index], &output_vstream_size);
+ REQUIRE_SUCCESS(status, l_release_hef, "Failed making output virtual stream params");
+ REQUIRE_ACTION(output_vstream_size == 1, status = HAILO_INVALID_ARGUMENT, l_release_hef,
+ "INVALID HEF - Only hefs with single output vstream are allowed");
+ }
+
+ input_args.configured_networks = network_groups;
+ input_args.input_vstream_params = input_vstream_params;
+
+ // Open input vstream and output vstream threads
+ status = hailo_create_thread(input_vstream_thread_func, &input_args, &input_vstream_thread);
+ REQUIRE_SUCCESS(status, l_release_hef, "Failed creating thread");
+
+ output_args.configured_networks = network_groups;
+ output_args.activated_network_group = &activated_network;
+ output_args.output_vstream_params = output_vstream_params;
+
+ // Open output vstream and output vstream threads
+ status = hailo_create_thread(output_vstream_thread_func, &output_args, &output_vstream_thread);
+ REQUIRE_SUCCESS(status, l_join_input_thread, "Failed creating thread");
+
+ // Activate first network so input thread can start
+ status = hailo_activate_network_group(network_groups[0], NULL, &activated_network);
+ REQUIRE_SUCCESS(status, l_join_output_thread, "Failed Activating network");
+
+
+ status = hailo_join_thread(&input_vstream_thread);
+ REQUIRE_SUCCESS(status, l_join_output_thread, "Failed witing for input thread");
+
+ status = hailo_join_thread(&output_vstream_thread);
+ REQUIRE_SUCCESS(status, l_join_output_thread, "Failed witing for output thread");
+
+ printf("Inference ran successfully\n");
+ status = HAILO_SUCCESS;
+ goto l_release_hef;
+
+l_join_output_thread:
+ (void)hailo_join_thread(&output_vstream_thread);
+l_join_input_thread:
+ (void)hailo_join_thread(&input_vstream_thread);
+l_release_hef:
+ for (hef_index = 0; hef_index < HEF_COUNT; hef_index++) {
+ if (NULL != hef[hef_index]) {
+ (void)hailo_release_hef(hef[hef_index]);
+ }
+ }
+ (void)hailo_release_vdevice(vdevice);
+l_exit:
+ return status;
+}
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
**/
/**
- * @ file vstreams_example.c
+ * @file vstreams_example.c
* This example demonstrates the basic data-path on HailoRT using the high level API - Virtual Stream Pipeline.
* The program scans for Hailo-8 devices connected to a provided PCIe interface, generates random dataset,
* and runs it through the VDevice with virtual streams.
+++ /dev/null
-# - Try to find HailoRT
-# - If libhailort is defined (building as part of the build tree), use it
-# - Otherwise, find HAILORT_LIB and HAILORT_INCLUDE_DIR, and import libhailort
-
-if (NOT TARGET libhailort)
- # find_path finds a directory containing the named file
- if(WIN32)
- find_library(HAILORT_LIB "libhailort.lib" PATH_SUFFIXES "HailoRT/lib/")
- find_path(HAILORT_INCLUDE_DIR "hailo/" PATH_SUFFIXES "HailoRT/include/")
-
- else()
- find_library(HAILORT_LIB "libhailort.so.4.6.0" PATH_SUFFIXES "lib/")
- find_path(HAILORT_INCLUDE_DIR "hailo/" PATH_SUFFIXES "include/")
- endif()
-
- include(FindPackageHandleStandardArgs)
- # Handle the QUIETLY and REQUIRED arguments and set HAILORT_FOUND to TRUE
- # if all listed variables are TRUE
- find_package_handle_standard_args(
- HailoRT
- DEFAULT_MSG
- HAILORT_LIB
- HAILORT_INCLUDE_DIR
- )
-
- add_library(HailoRT::libhailort SHARED IMPORTED)
- set_target_properties(HailoRT::libhailort PROPERTIES
- IMPORTED_LOCATION "${HAILORT_LIB}"
- IMPORTED_IMPLIB "${HAILORT_LIB}"
- INTERFACE_INCLUDE_DIRECTORIES "${HAILORT_INCLUDE_DIR}"
- )
-
-else()
- add_library(HailoRT::libhailort ALIAS libhailort)
-endif()
add_executable(cpp_multi_network_vstream_example multi_network_vstream_example.cpp)
target_link_libraries(cpp_multi_network_vstream_example PRIVATE example_base)
-add_executable(cpp_switch_hefs_example switch_hefs_example.cpp)
-target_link_libraries(cpp_switch_hefs_example PRIVATE example_base)
+add_executable(cpp_switch_network_groups_example switch_network_groups_example.cpp)
+target_link_libraries(cpp_switch_network_groups_example PRIVATE example_base)
-add_executable(cpp_switch_hefs_example_threads_reuse switch_hefs_example_threads_reuse.cpp)
-target_link_libraries(cpp_switch_hefs_example_threads_reuse PRIVATE example_base)
+add_executable(cpp_switch_network_groups_manually_example switch_network_groups_manually_example.cpp)
+target_link_libraries(cpp_switch_network_groups_manually_example PRIVATE example_base)
-add_executable(multi_device_example_cpp multi_device_example.cpp)
-target_link_libraries(multi_device_example_cpp PRIVATE example_base)
+add_executable(cpp_multi_device_example multi_device_example.cpp)
+target_link_libraries(cpp_multi_device_example PRIVATE example_base)
+
+add_executable(cpp_power_measurement_example power_measurement_example.cpp)
+target_link_libraries(cpp_power_measurement_example PRIVATE example_base)
set(EXAMPLES_CPP_TARGETS
cpp_vstreams_example
cpp_infer_pipeline_example
cpp_raw_streams_example
cpp_multi_network_vstream_example
- cpp_switch_hefs_example
- cpp_switch_hefs_example_threads_reuse
- multi_device_example_cpp
+ cpp_switch_network_groups_example
+ cpp_switch_network_groups_manually_example
+ cpp_multi_device_example
+ cpp_power_measurement_example
PARENT_SCOPE)
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
**/
/**
- * @ file vstreams_example
+ * @file vstreams_example
* This example demonstrates the basic data-path on HailoRT using the high level API - Virtual Stream Pipeline.
* The program creates a device according to the provdied IP address, generates a random dataset,
* and runs it through the device with virtual streams pipeline.
#define USAGE_ERROR_MSG ("Args parsing error.\nUsage: infer_pipeline_example <ip_address>\n")
-
-using hailort::Device;
-using hailort::Hef;
-using hailort::Expected;
-using hailort::make_unexpected;
-using hailort::ConfiguredNetworkGroup;
-using hailort::MemoryView;
-using hailort::InferVStreams;
-
+using namespace hailort;
Expected<std::shared_ptr<ConfiguredNetworkGroup>> configure_network_group(Device &device)
{
* You shall not reproduce, modify or distribute this software without prior written permission.
**/
/**
- * @ file multi_device_example.cpp
+ * @file multi_device_example.cpp
* This example demonstrates how to work with multiple devices using virtual device.
**/
constexpr hailo_format_type_t FORMAT_TYPE = HAILO_FORMAT_TYPE_AUTO;
constexpr size_t MAX_LAYER_EDGES = 16;
-
-using hailort::VDevice;
-using hailort::Hef;
-using hailort::Expected;
-using hailort::make_unexpected;
-using hailort::ConfiguredNetworkGroup;
-using hailort::VStreamsBuilder;
-using hailort::InputVStream;
-using hailort::OutputVStream;
-using hailort::MemoryView;
-
+using namespace hailort;
Expected<std::shared_ptr<ConfiguredNetworkGroup>> configure_network_group(VDevice &vdevice)
{
constexpr size_t SECOND_NET_BATCH_SIZE = 2;
constexpr uint32_t DEVICE_COUNT = 1;
-using hailort::VDevice;
-using hailort::Hef;
-using hailort::Expected;
-using hailort::make_unexpected;
-using hailort::ConfiguredNetworkGroup;
-using hailort::VStreamsBuilder;
-using hailort::InputVStream;
-using hailort::OutputVStream;
-using hailort::MemoryView;
+using namespace hailort;
using InOutVStreams = std::pair<std::vector<InputVStream>, std::vector<OutputVStream>>;
-
Expected<std::shared_ptr<ConfiguredNetworkGroup>> configure_network_group(VDevice &vdevice, Hef &hef, uint16_t batch_size[NET_COUNT])
{
auto configure_params = hef.create_configure_params(HAILO_STREAM_INTERFACE_PCIE);
auto network_infos = get_network_infos(*network_group.value());
if (!network_infos) {
std::cerr << "Failed to get network infos, status = " << network_infos.status() << std::endl;
- return network_group.status();
+ return network_infos.status();
}
auto vstreams = create_vstreams_per_network(*network_group.value(), network_infos.value());
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file power_measurement_example.cpp
+ * This example demonstrates power and current measurements.
+ **/
+
+#include "hailo/hailort.hpp"
+
+#include <iostream>
+#include <chrono>
+#include <thread>
+
+#define SAMPLING_PERIOD (HAILO_SAMPLING_PERIOD_1100US)
+#define AVERAGE_FACTOR (HAILO_AVERAGE_FACTOR_256)
+#define DVM_OPTION (HAILO_DVM_OPTIONS_AUTO) // For current measurement over EVB - pass DVM explicitly (see hailo_dvm_options_t)
+#define MEASUREMENT_BUFFER_INDEX (HAILO_MEASUREMENT_BUFFER_INDEX_0)
+
+#define MEASUREMENT_UNITS(__type) \
+ ((HAILO_POWER_MEASUREMENT_TYPES__POWER == __type) ? ("W") : ("mA"))
+
+#define USAGE_ERROR_MSG ("Args parsing error.\nUsage: power_measurement_example [power / current]\n" \
+ "* power - measure power consumption in W\n" \
+ "* current - measure current in mA\n")
+
+const std::string POWER_ARG = "power";
+const std::string CURRENT_ARG = "current";
+
+const std::chrono::seconds MEASUREMENTS_DURATION_SECS(5);
+
+using namespace hailort;
+
+Expected<hailo_power_measurement_types_t> parse_arguments(int argc, char **argv)
+{
+ if (2 != argc) {
+ std::cerr << USAGE_ERROR_MSG << std::endl;
+ return make_unexpected(HAILO_INVALID_ARGUMENT);
+ }
+
+ if (POWER_ARG == std::string(argv[1])) {
+ return HAILO_POWER_MEASUREMENT_TYPES__POWER;
+ } else if (CURRENT_ARG == std::string(argv[1])) {
+ return HAILO_POWER_MEASUREMENT_TYPES__CURRENT;
+ } else {
+ std::cerr << USAGE_ERROR_MSG << std::endl;
+ return make_unexpected(HAILO_INVALID_ARGUMENT);
+ }
+}
+
+void print_measurements_results(Device &device, const hailo_power_measurement_data_t &result, hailo_power_measurement_types_t type)
+{
+ auto id = device.get_dev_id();
+
+ auto type_str = (type == HAILO_POWER_MEASUREMENT_TYPES__POWER) ? "Power measurement" :
+ "Current measurement";
+
+ std::cout << "Device" << std::string(id) << ":" << std::endl;
+ std::cout << " " << type_str << std::endl;
+ std::cout << " Minimum value: " << result.min_value << MEASUREMENT_UNITS(type) << std::endl;
+ std::cout << " Average value: " << result.average_value << MEASUREMENT_UNITS(type) << std::endl;
+ std::cout << " Maximum value: " << result.max_value << MEASUREMENT_UNITS(type) << std::endl;
+}
+
+int main(int argc, char **argv)
+{
+ auto measurement_type = parse_arguments(argc, argv);
+ if (!measurement_type) {
+ return measurement_type.status();
+ }
+
+ auto scan_res = Device::scan_pcie();
+ if (!scan_res) {
+ std::cerr << "Failed to scan pcie_device" << std::endl;
+ return scan_res.status();
+ }
+
+ hailo_vdevice_params_t params;
+ auto status = hailo_init_vdevice_params(¶ms);
+ if (HAILO_SUCCESS != status) {
+ std::cerr << "Failed init vdevice_params, status = " << status << std::endl;
+ return status;
+ }
+
+ params.device_count = static_cast<uint32_t>(scan_res->size());
+ auto vdevice = VDevice::create(params);
+ if (!vdevice) {
+ std::cerr << "Failed create vdevice, status = " << vdevice.status() << std::endl;
+ return vdevice.status();
+ }
+
+ auto physical_devices = vdevice.value()->get_physical_devices();
+ if (!physical_devices) {
+ std::cerr << "Failed to get physical devices" << std::endl;
+ return physical_devices.status();
+ }
+
+ for (auto &physical_device : physical_devices.value()) {
+ status = physical_device.get().stop_power_measurement();
+ if (HAILO_SUCCESS != status) {
+ std::cerr << "Failed stopping former measurements" << std::endl;
+ return status;
+ }
+
+ status = physical_device.get().set_power_measurement(MEASUREMENT_BUFFER_INDEX, DVM_OPTION, measurement_type.value());
+ if (HAILO_SUCCESS != status) {
+ std::cerr << "Failed setting measurement params" << std::endl;
+ return status;
+ }
+
+ status = physical_device.get().start_power_measurement(AVERAGE_FACTOR, SAMPLING_PERIOD);
+ if (HAILO_SUCCESS != status) {
+ std::cerr << "Failed to start measurement" << std::endl;
+ return status;
+ }
+ }
+
+ std::this_thread::sleep_for(MEASUREMENTS_DURATION_SECS);
+
+ for (auto &physical_device : physical_devices.value()) {
+ status = physical_device.get().stop_power_measurement();
+ if (HAILO_SUCCESS != status) {
+ std::cerr << "Failed to stop measurement" << std::endl;
+ return status;
+ }
+
+ auto measurement_result = physical_device.get().get_power_measurement(MEASUREMENT_BUFFER_INDEX, true);
+ if (!measurement_result) {
+ std::cerr << "Failed to get measurement results" << std::endl;
+ return measurement_result.status();
+ }
+
+ print_measurements_results(physical_device.get(), measurement_result.value(), measurement_type.value());
+ }
+
+ return HAILO_SUCCESS;
+}
\ No newline at end of file
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
**/
/**
- * @ file raw_streams_example
+ * @file raw_streams_example
* This example demonstrates using low level streams over c++
**/
constexpr hailo_format_type_t FORMAT_TYPE = HAILO_FORMAT_TYPE_AUTO;
constexpr size_t MAX_LAYER_EDGES = 16;
-using hailort::Device;
-using hailort::Hef;
-using hailort::Expected;
-using hailort::make_unexpected;
-using hailort::ConfiguredNetworkGroup;
-using hailort::VStreamsBuilder;
-using hailort::InputStream;
-using hailort::InputTransformContext;
-using hailort::OutputTransformContext;
-using hailort::OutputStream;
-using hailort::MemoryView;
-using hailort::InputStreamRefVector;
-using hailort::OutputStreamRefVector;
-
+using namespace hailort;
Expected<std::shared_ptr<ConfiguredNetworkGroup>> configure_network_group(Device &device)
{
int main()
{
auto device = Device::create_pcie();
+ /*
+ For simplicity, not passing `device_info` - This function will fail in case more than one PCIe device is present.
+ See `hailort::Device::scan_pcie` and `hailort::Device::create_pcie` functions documentation.
+ */
if (!device) {
std::cerr << "Failed create_pcie " << device.status() << std::endl;
return device.status();
+++ /dev/null
-/**
- * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
- * Distributed under the MIT license (https://opensource.org/licenses/MIT)
- **/
-/**
- * @ file switch_hefs_example.cpp
- * This example demonstrates basic usage of HailoRT streaming api over multiple network groups, using vstreams.
- * It loads several HEF networks with single/multiple inputs and single/multiple outputs into a Hailo PCIe VDevice and performs a
- * short inference on each one.
- * After inference is finished, the example switches to the next HEF and start inference again.
- **/
-
-#include "hailo/hailort.hpp"
-
-#include <iostream>
-#include <chrono>
-
-constexpr bool QUANTIZED = true;
-constexpr hailo_format_type_t FORMAT_TYPE = HAILO_FORMAT_TYPE_AUTO;
-constexpr size_t INFER_FRAME_COUNT = 100;
-constexpr size_t RUN_COUNT = 10;
-constexpr uint32_t DEVICE_COUNT = 1;
-
-
-using hailort::VDevice;
-using hailort::Hef;
-using hailort::Expected;
-using hailort::make_unexpected;
-using hailort::ConfiguredNetworkGroup;
-using hailort::VStreamsBuilder;
-using hailort::InputVStream;
-using hailort::OutputVStream;
-using hailort::MemoryView;
-
-
-void write_all(InputVStream &input_vstream, hailo_status &status_out)
-{
- std::vector<uint8_t> buff(input_vstream.get_frame_size());
-
- for (size_t i = 0; i < INFER_FRAME_COUNT; i++) {
- auto status = input_vstream.write(MemoryView(buff.data(), buff.size()));
- if (HAILO_SUCCESS != status) {
- status_out = status;
- return;
- }
- }
- return;
-}
-
-void read_all(OutputVStream &output_vstream, hailo_status &status_out)
-{
- std::vector<uint8_t> buff(output_vstream.get_frame_size());
-
- for (size_t i = 0; i < INFER_FRAME_COUNT; i++) {
- auto status = output_vstream.read(MemoryView(buff.data(), buff.size()));
- if (HAILO_SUCCESS != status) {
- status_out = status;
- return;
- }
- }
- return;
-}
-
-Expected<std::vector<std::pair<std::vector<InputVStream>, std::vector<OutputVStream>>>> build_vstreams(
- const std::vector<std::shared_ptr<ConfiguredNetworkGroup>> &configured_network_groups)
-{
- std::vector<std::pair<std::vector<InputVStream>, std::vector<OutputVStream>>> vstreams_per_network_group;
-
- for (auto &network_group : configured_network_groups) {
- auto vstreams_exp = VStreamsBuilder::create_vstreams(*network_group, QUANTIZED, FORMAT_TYPE);
- if (!vstreams_exp) {
- return make_unexpected(vstreams_exp.status());
- }
- vstreams_per_network_group.emplace_back(vstreams_exp.release());
- }
- return vstreams_per_network_group;
-}
-
-std::vector<std::unique_ptr<std::thread>> create_read_threads(std::vector<OutputVStream> &vstreams,
- std::vector<hailo_status> &read_results)
-{
- std::vector<std::unique_ptr<std::thread>> read_threads;
-
- read_results.reserve(vstreams.size());
- for (auto &vstream : vstreams) {
- read_results.push_back(HAILO_SUCCESS); // Success oriented
- read_threads.emplace_back(std::make_unique<std::thread>(read_all,
- std::ref(vstream), std::ref(read_results.back())));
- }
- return read_threads;
-}
-
-std::vector<std::unique_ptr<std::thread>> create_write_threads(std::vector<InputVStream> &vstreams,
- std::vector<hailo_status> &write_results)
-{
- std::vector<std::unique_ptr<std::thread>> write_threads;
-
- write_results.reserve(vstreams.size());
- for (auto &vstream : vstreams) {
- write_results.push_back(HAILO_SUCCESS); // Success oriented
- write_threads.emplace_back(std::make_unique<std::thread>(write_all,
- std::ref(vstream), std::ref(write_results.back())));
- }
- return write_threads;
-}
-
-int main()
-{
- hailo_vdevice_params_t params;
- auto status = hailo_init_vdevice_params(¶ms);
- if (HAILO_SUCCESS != status) {
- std::cerr << "Failed init vdevice_params, status = " << status << std::endl;
- return status;
- }
-
- params.device_count = DEVICE_COUNT;
- auto vdevice_exp = VDevice::create(params);
- if (!vdevice_exp) {
- std::cerr << "Failed create vdevice, status = " << vdevice_exp.status() << std::endl;
- return vdevice_exp.status();
- }
- auto vdevice = vdevice_exp.release();
-
- std::vector<std::string> hef_paths = {"hefs/shortcut_net.hef", "hefs/shortcut_net.hef"};
- std::vector<std::shared_ptr<ConfiguredNetworkGroup>> configured_network_groups;
-
- for (const auto &path : hef_paths) {
- auto hef_exp = Hef::create(path);
- if (!hef_exp) {
- std::cerr << "Failed to create hef: " << path << ", status = " << hef_exp.status() << std::endl;
- return hef_exp.status();
- }
- auto hef = hef_exp.release();
-
- auto added_network_groups = vdevice->configure(hef);
- if (!added_network_groups) {
- std::cerr << "Failed to configure vdevice, status = " << added_network_groups.status() << std::endl;
- return added_network_groups.status();
- }
- configured_network_groups.insert(configured_network_groups.end(), added_network_groups->begin(),
- added_network_groups->end());
- }
-
- auto vstreams_per_network_group_exp = build_vstreams(configured_network_groups);
- if (!vstreams_per_network_group_exp) {
- std::cerr << "Failed to create vstreams, status = " << vstreams_per_network_group_exp.status() << std::endl;
- return vstreams_per_network_group_exp.status();
- }
- auto vstreams_per_network_group = vstreams_per_network_group_exp.release();
-
- for (size_t i = 0; i < RUN_COUNT; i++) {
- for (size_t network_group_idx = 0; network_group_idx < configured_network_groups.size(); network_group_idx++) {
- auto activated_network_group_exp = configured_network_groups[network_group_idx]->activate();
-
- if (!activated_network_group_exp) {
- std::cerr << "Failed to activate network group, status = " << activated_network_group_exp.status() << std::endl;
- return activated_network_group_exp.status();
- }
-
- // Create send/recv threads
- std::vector<hailo_status> read_results;
- auto read_threads = create_read_threads(vstreams_per_network_group[network_group_idx].second, read_results);
-
- std::vector<hailo_status> write_results;
- auto write_threads = create_write_threads(vstreams_per_network_group[network_group_idx].first, write_results);
-
- // Join threads and validate results
- for (auto &th : write_threads) {
- if (th->joinable()) {
- th->join();
- }
- }
- for (auto &th : read_threads) {
- if (th->joinable()) {
- th->join();
- }
- }
-
- for (auto &thread_status : write_results) {
- if (HAILO_SUCCESS != thread_status) {
- std::cerr << "Inference failed, status = " << thread_status << std::endl;
- return thread_status;
- }
- }
- for (auto &thread_status : read_results) {
- if (HAILO_SUCCESS != thread_status) {
- std::cerr << "Inference failed, status = " << thread_status << std::endl;
- return thread_status;
- }
- }
- }
- }
-
- std::cout << "Inference finished successfully" << std::endl;
- return HAILO_SUCCESS;
-}
\ No newline at end of file
+++ /dev/null
-/**
- * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
- * Distributed under the MIT license (https://opensource.org/licenses/MIT)
- **/
-/**git checkout HRT-4862-change-switch_hefs_example-to-r
- * @ file switch_hefs_example_threads_reuse.cpp
- * This example demonstrates basic usage of HailoRT streaming api over multiple networks, using vstreams.
- * It loads several HEF networks with single/multiple inputs and single/multiple outputs into a Hailo PCIe VDevice and performs a
- * short inference on each one.
- * After inference is finished, the example switches to the next HEF and start inference again.
- **/
-
-#include "hailo/hailort.hpp"
-
-#include <iostream>
-#include <chrono>
-
-constexpr bool QUANTIZED = true;
-constexpr hailo_format_type_t FORMAT_TYPE = HAILO_FORMAT_TYPE_AUTO;
-
-constexpr size_t INFER_FRAME_COUNT = 100;
-constexpr size_t RUN_COUNT = 10;
-constexpr std::chrono::milliseconds WAIT_FOR_ACTIVATION_TIMEOUT_MS(10);
-constexpr uint32_t DEVICE_COUNT = 1;
-
-using hailort::VDevice;
-using hailort::Hef;
-using hailort::ConfiguredNetworkGroup;
-using hailort::ActivatedNetworkGroup;
-using hailort::VStreamsBuilder;
-using hailort::InputVStream;
-using hailort::OutputVStream;
-using hailort::MemoryView;
-
-
-#include <mutex>
-#include <condition_variable>
-
-class SyncObject final {
-/* Synchronization class used to make sure I/O threads are blocking while their network_group is not activated */
-public:
- explicit SyncObject(size_t count) : m_original_count(count), m_count(count), m_all_arrived(false), m_mutex(), m_cv(), m_is_active(true)
- {};
-
- /* In main thread we wait until I/O threads are done (0 == m_count),
- signaling the I/O threads only after deactivating their network_group and resetting m_count to m_original_count */
- void wait_all(std::unique_ptr<ActivatedNetworkGroup> &&activated_network_group)
- {
- if (!m_is_active.load()) {
- return;
- }
- std::unique_lock<std::mutex> lock(m_mutex);
- m_cv.wait(lock, [this] { return ((0 == m_count) || !m_is_active); });
- activated_network_group.reset();
- m_count = m_original_count;
- m_all_arrived = true;
- m_cv.notify_all();
- }
-
- /* In I/O threads we wait until signaled by main thread (true == m_all_arrived),
- resetting m_all_arrived to false to make sure it was setted by 'wait_all' call */
- void notify_and_wait()
- {
- if (!m_is_active.load()) {
- return;
- }
- std::unique_lock<std::mutex> lock(m_mutex);
- m_all_arrived = false;
- --m_count;
- m_cv.notify_all();
- m_cv.wait(lock, [this] { return ((m_all_arrived) || !m_is_active); });
- }
-
- void terminate()
- {
- {
- std::unique_lock<std::mutex> lock(m_mutex);
- m_is_active.store(false);
- }
- m_cv.notify_all();
- }
-
-private:
- const size_t m_original_count;
- std::atomic_size_t m_count;
- std::atomic_bool m_all_arrived;
-
- std::mutex m_mutex;
- std::condition_variable m_cv;
- std::atomic_bool m_is_active;
-};
-
-
-void write_all(std::shared_ptr<ConfiguredNetworkGroup> network_group, InputVStream &input_vstream,
- std::shared_ptr<SyncObject> sync_object, std::shared_ptr<std::atomic_bool> should_threads_run, hailo_status &status_out)
-{
- std::vector<uint8_t> buff(input_vstream.get_frame_size());
-
- auto status = HAILO_UNINITIALIZED;
- while (true) {
- if (!(*should_threads_run)) {
- break;
- }
- status = network_group->wait_for_activation(WAIT_FOR_ACTIVATION_TIMEOUT_MS);
- if (HAILO_TIMEOUT == status) {
- continue;
- } else if (HAILO_SUCCESS != status) {
- std::cerr << "Wait for network group activation failed. status = " << status << std::endl;
- status_out = status;
- return;
- }
-
- for (size_t i = 0; i < INFER_FRAME_COUNT; i++) {
- status = input_vstream.write(MemoryView(buff.data(), buff.size()));
- if (HAILO_SUCCESS != status) {
- status_out = status;
- return;
- }
- }
- sync_object->notify_and_wait();
- }
- return;
-}
-
-void read_all(std::shared_ptr<ConfiguredNetworkGroup> network_group, OutputVStream &output_vstream,
- std::shared_ptr<SyncObject> sync_object, std::shared_ptr<std::atomic_bool> should_threads_run, hailo_status &status_out)
-{
- std::vector<uint8_t> buff(output_vstream.get_frame_size());
-
- auto status = HAILO_UNINITIALIZED;
- while (true) {
- if (!(*should_threads_run)) {
- break;
- }
- status = network_group->wait_for_activation(WAIT_FOR_ACTIVATION_TIMEOUT_MS);
- if (HAILO_TIMEOUT == status) {
- continue;
- } else if (HAILO_SUCCESS != status) {
- std::cerr << "Wait for network group activation failed. status = " << status << std::endl;
- status_out = status;
- return;
- }
-
- for (size_t i = 0; i < INFER_FRAME_COUNT; i++) {
- status = output_vstream.read(MemoryView(buff.data(), buff.size()));
- if (HAILO_SUCCESS != status) {
- status_out = status;
- return;
- }
- }
- sync_object->notify_and_wait();
- }
- return;
-}
-
-void network_group_thread_main(std::shared_ptr<ConfiguredNetworkGroup> network_group, std::shared_ptr<SyncObject> sync_object,
- std::shared_ptr<std::atomic_bool> should_threads_run, hailo_status &status_out)
-{
- // Create VStreams
- auto vstreams_exp = VStreamsBuilder::create_vstreams(*network_group, QUANTIZED, FORMAT_TYPE);
- if (!vstreams_exp) {
- std::cerr << "Failed to create vstreams, status = " << vstreams_exp.status() << std::endl;
- status_out = vstreams_exp.status();
- return;
- }
-
- // Create send/recv loops
- std::vector<std::unique_ptr<std::thread>> recv_ths;
- std::vector<hailo_status> read_results;
- read_results.reserve(vstreams_exp->second.size());
- for (auto &vstream : vstreams_exp->second) {
- read_results.push_back(HAILO_SUCCESS); // Success oriented
- recv_ths.emplace_back(std::make_unique<std::thread>(read_all,
- network_group, std::ref(vstream), sync_object, should_threads_run, std::ref(read_results.back())));
- }
-
- std::vector<std::unique_ptr<std::thread>> send_ths;
- std::vector<hailo_status> write_results;
- write_results.reserve(vstreams_exp->first.size());
- for (auto &vstream : vstreams_exp->first) {
- write_results.push_back(HAILO_SUCCESS); // Success oriented
- send_ths.emplace_back(std::make_unique<std::thread>(write_all,
- network_group, std::ref(vstream), std::ref(sync_object), should_threads_run, std::ref(write_results.back())));
- }
-
- for (auto &send_th : send_ths) {
- if (send_th->joinable()) {
- send_th->join();
- }
- }
- for (auto &recv_th : recv_ths) {
- if (recv_th->joinable()) {
- recv_th->join();
- }
- }
-
- for (auto &status : read_results) {
- if (HAILO_SUCCESS != status) {
- status_out = status;
- return;
- }
- }
- for (auto &status : write_results) {
- if (HAILO_SUCCESS != status) {
- status_out = status;
- return;
- }
- }
- status_out = HAILO_SUCCESS;
- return;
-}
-
-int main()
-{
- hailo_vdevice_params_t params;
- auto status = hailo_init_vdevice_params(¶ms);
- if (HAILO_SUCCESS != status) {
- std::cerr << "Failed init vdevice_params, status = " << status << std::endl;
- return status;
- }
-
- params.device_count = DEVICE_COUNT;
- auto vdevice_exp = VDevice::create(params);
- if (!vdevice_exp) {
- std::cerr << "Failed create vdevice, status = " << vdevice_exp.status() << std::endl;
- return vdevice_exp.status();
- }
- auto vdevice = vdevice_exp.release();
-
- std::vector<std::string> hef_paths = {"hefs/shortcut_net.hef", "hefs/shortcut_net.hef"};
- std::vector<std::shared_ptr<ConfiguredNetworkGroup>> configured_network_groups;
-
- for (const auto &path : hef_paths) {
- auto hef_exp = Hef::create(path);
- if (!hef_exp) {
- std::cerr << "Failed to create hef: " << path << ", status = " << hef_exp.status() << std::endl;
- return hef_exp.status();
- }
- auto hef = hef_exp.release();
-
- auto added_network_groups = vdevice->configure(hef);
- if (!added_network_groups) {
- std::cerr << "Failed to configure vdevice, status = " << added_network_groups.status() << std::endl;
- return added_network_groups.status();
- }
- configured_network_groups.insert(configured_network_groups.end(), added_network_groups->begin(), added_network_groups->end());
- }
-
- auto should_threads_run = std::make_shared<std::atomic_bool>(true);
-
- std::vector<std::shared_ptr<SyncObject>> sync_objects;
- sync_objects.reserve(configured_network_groups.size());
- std::vector<hailo_status> threads_results;
- threads_results.reserve(configured_network_groups.size());
- std::vector<std::unique_ptr<std::thread>> network_group_threads;
- network_group_threads.reserve(configured_network_groups.size());
-
- for (auto network_group : configured_network_groups) {
- threads_results.push_back(HAILO_UNINITIALIZED);
- auto vstream_infos = network_group->get_all_vstream_infos();
- if (!vstream_infos) {
- std::cerr << "Failed to get vstream infos, status = " << vstream_infos.status() << std::endl;
- return vstream_infos.status();
- }
- sync_objects.emplace_back((std::make_shared<SyncObject>(vstream_infos->size())));
- network_group_threads.emplace_back(std::make_unique<std::thread>(network_group_thread_main,
- network_group, sync_objects.back(), should_threads_run, std::ref(threads_results.back())));
- }
-
- for (size_t i = 0; i < RUN_COUNT; i++) {
- for (size_t network_group_idx = 0; network_group_idx < configured_network_groups.size(); network_group_idx++) {
- auto activated_network_group_exp = configured_network_groups[network_group_idx]->activate();
- if (!activated_network_group_exp) {
- std::cerr << "Failed to activate network group, status = " << activated_network_group_exp.status() << std::endl;
- return activated_network_group_exp.status();
- }
- sync_objects[network_group_idx]->wait_all(activated_network_group_exp.release());
- }
- }
-
- *should_threads_run = false;
- for (auto &sync_object : sync_objects) {
- sync_object->terminate();
- }
-
- for (auto &th : network_group_threads) {
- if (th->joinable()) {
- th->join();
- }
- }
-
- for (auto &thread_status : threads_results) {
- if (HAILO_SUCCESS != thread_status) {
- std::cerr << "Inference failed, status = " << thread_status << std::endl;
- return thread_status;
- }
- }
-
- std::cout << "Inference finished successfully" << std::endl;
- return HAILO_SUCCESS;
-}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file switch_network_groups_example.cpp
+ * This example demonstrates basic usage of HailoRT streaming api over multiple network groups, using VStreams.
+ * It loads several network_groups (via several HEFs) into a Hailo PCIe VDevice and performs a inferences on all of them in parallel.
+ * The network_groups switching is performed automatically by the HailoRT scheduler.
+ **/
+
+#include "hailo/hailort.hpp"
+
+#include <iostream>
+#include <chrono>
+
+constexpr bool QUANTIZED = true;
+constexpr hailo_format_type_t FORMAT_TYPE = HAILO_FORMAT_TYPE_AUTO;
+constexpr size_t INFER_FRAME_COUNT = 100;
+constexpr uint32_t DEVICE_COUNT = 1;
+
+using namespace hailort;
+using ThreadsVector = std::vector<std::unique_ptr<std::thread>>;
+using StatusVector = std::vector<std::shared_ptr<hailo_status>>;
+
+void write_all(InputVStream &input_vstream, std::shared_ptr<hailo_status> status_out)
+{
+ std::vector<uint8_t> buff(input_vstream.get_frame_size());
+
+ for (size_t i = 0; i < INFER_FRAME_COUNT; i++) {
+ auto status = input_vstream.write(MemoryView(buff.data(), buff.size()));
+ if (HAILO_SUCCESS != status) {
+ *status_out = status;
+ return;
+ }
+ }
+ *status_out = HAILO_SUCCESS;
+ return;
+}
+
+void read_all(OutputVStream &output_vstream, std::shared_ptr<hailo_status> status_out)
+{
+ std::vector<uint8_t> buff(output_vstream.get_frame_size());
+
+ for (size_t i = 0; i < INFER_FRAME_COUNT; i++) {
+ auto status = output_vstream.read(MemoryView(buff.data(), buff.size()));
+ if (HAILO_SUCCESS != status) {
+ *status_out = status;
+ return;
+ }
+ }
+ *status_out = HAILO_SUCCESS;
+ return;
+}
+
+Expected<std::vector<std::pair<std::vector<InputVStream>, std::vector<OutputVStream>>>> build_vstreams(
+ const std::vector<std::shared_ptr<ConfiguredNetworkGroup>> &configured_network_groups)
+{
+ std::vector<std::pair<std::vector<InputVStream>, std::vector<OutputVStream>>> vstreams_per_network_group;
+
+ for (auto &network_group : configured_network_groups) {
+ auto vstreams_exp = VStreamsBuilder::create_vstreams(*network_group, QUANTIZED, FORMAT_TYPE);
+ if (!vstreams_exp) {
+ return make_unexpected(vstreams_exp.status());
+ }
+ vstreams_per_network_group.emplace_back(vstreams_exp.release());
+ }
+ return vstreams_per_network_group;
+}
+
+void create_read_threads(std::vector<OutputVStream> &vstreams, StatusVector &read_results, ThreadsVector &threads_vector)
+{
+ for (auto &vstream : vstreams) {
+ read_results.push_back(std::make_shared<hailo_status>(HAILO_UNINITIALIZED));
+ threads_vector.emplace_back(std::make_unique<std::thread>(read_all, std::ref(vstream), read_results.back()));
+ }
+}
+
+void create_write_threads(std::vector<InputVStream> &vstreams, StatusVector &write_results, ThreadsVector &threads_vector)
+{
+ for (auto &vstream : vstreams) {
+ write_results.push_back(std::make_shared<hailo_status>(HAILO_UNINITIALIZED));
+ threads_vector.emplace_back(std::make_unique<std::thread>(write_all, std::ref(vstream), write_results.back()));
+ }
+}
+
+Expected<std::unique_ptr<VDevice>> create_vdevice()
+{
+ hailo_vdevice_params_t params;
+ auto status = hailo_init_vdevice_params(¶ms);
+ if (HAILO_SUCCESS != status) {
+ std::cerr << "Failed init vdevice_params, status = " << status << std::endl;
+ return make_unexpected(status);
+ }
+ params.scheduling_algorithm = HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN;
+ params.device_count = DEVICE_COUNT;
+
+ return VDevice::create(params);
+}
+
+Expected<std::vector<std::shared_ptr<ConfiguredNetworkGroup>>> configure_hefs(VDevice &vdevice, std::vector<std::string> &hef_paths)
+{
+ std::vector<std::shared_ptr<ConfiguredNetworkGroup>> results;
+
+ for (const auto &path : hef_paths) {
+ auto hef_exp = Hef::create(path);
+ if (!hef_exp) {
+ return make_unexpected(hef_exp.status());
+ }
+ auto hef = hef_exp.release();
+
+ auto added_network_groups = vdevice.configure(hef);
+ if (!added_network_groups) {
+ return make_unexpected(added_network_groups.status());
+ }
+ results.insert(results.end(), added_network_groups->begin(),
+ added_network_groups->end());
+ }
+ return results;
+}
+
+int main()
+{
+ auto vdevice_exp = create_vdevice();
+ if (!vdevice_exp) {
+ std::cerr << "Failed create vdevice, status = " << vdevice_exp.status() << std::endl;
+ return vdevice_exp.status();
+ }
+ auto vdevice = vdevice_exp.release();
+
+ std::vector<std::string> hef_paths = {"hefs/multi_network_shortcut_net.hef", "hefs/shortcut_net.hef"};
+ auto configured_network_groups_exp = configure_hefs(*vdevice, hef_paths);
+ if (!configured_network_groups_exp) {
+ std::cerr << "Failed to configure HEFs, status = " << configured_network_groups_exp.status() << std::endl;
+ return configured_network_groups_exp.status();
+ }
+ auto configured_network_groups = configured_network_groups_exp.release();
+
+ auto vstreams_per_network_group_exp = build_vstreams(configured_network_groups);
+ if (!vstreams_per_network_group_exp) {
+ std::cerr << "Failed to create vstreams, status = " << vstreams_per_network_group_exp.status() << std::endl;
+ return vstreams_per_network_group_exp.status();
+ }
+ auto vstreams_per_network_group = vstreams_per_network_group_exp.release();
+
+ ThreadsVector threads;
+ StatusVector results;
+
+ for (auto &vstreams_pair : vstreams_per_network_group) {
+ // Create send/recv threads
+ create_read_threads(vstreams_pair.second, results, threads);
+ create_write_threads(vstreams_pair.first, results, threads);
+ }
+
+ // Join threads and validate results
+ for (auto &thread : threads) {
+ if (thread->joinable()) {
+ thread->join();
+ }
+ }
+ for (auto &status : results) {
+ if (HAILO_SUCCESS != *status) {
+ std::cerr << "Inference failed, status = " << *status << std::endl;
+ return *status;
+ }
+ }
+
+ std::cout << "Inference finished successfully" << std::endl;
+ return HAILO_SUCCESS;
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file switch_network_groups_manually_example.cpp
+ * This example demonstrates basic usage of HailoRT streaming api over multiple networks, using vstreams.
+ * It loads several HEF networks with single/multiple inputs and single/multiple outputs into a Hailo PCIe VDevice and performs a
+ * short inference on each one.
+ * After inference is finished, the example switches to the next HEF and start inference again.
+ **/
+
+#include "hailo/hailort.hpp"
+
+#include <iostream>
+#include <chrono>
+
+constexpr bool QUANTIZED = true;
+constexpr hailo_format_type_t FORMAT_TYPE = HAILO_FORMAT_TYPE_AUTO;
+
+constexpr size_t INFER_FRAME_COUNT = 100;
+constexpr size_t RUN_COUNT = 10;
+constexpr std::chrono::milliseconds WAIT_FOR_ACTIVATION_TIMEOUT_MS(10);
+constexpr uint32_t DEVICE_COUNT = 1;
+
+using namespace hailort;
+
+#include <mutex>
+#include <condition_variable>
+
+class SyncObject final {
+/* Synchronization class used to make sure I/O threads are blocking while their network_group is not activated */
+public:
+ explicit SyncObject(size_t count) : m_original_count(count), m_count(count), m_all_arrived(false), m_mutex(), m_cv(), m_is_active(true)
+ {};
+
+ /* In main thread we wait until I/O threads are done (0 == m_count),
+ signaling the I/O threads only after deactivating their network_group and resetting m_count to m_original_count */
+ void wait_all(std::unique_ptr<ActivatedNetworkGroup> &&activated_network_group)
+ {
+ if (!m_is_active.load()) {
+ return;
+ }
+ std::unique_lock<std::mutex> lock(m_mutex);
+ m_cv.wait(lock, [this] { return ((0 == m_count) || !m_is_active); });
+ activated_network_group.reset();
+ m_count = m_original_count;
+ m_all_arrived = true;
+ m_cv.notify_all();
+ }
+
+ /* In I/O threads we wait until signaled by main thread (true == m_all_arrived),
+ resetting m_all_arrived to false to make sure it was setted by 'wait_all' call */
+ void notify_and_wait()
+ {
+ if (!m_is_active.load()) {
+ return;
+ }
+ std::unique_lock<std::mutex> lock(m_mutex);
+ m_all_arrived = false;
+ --m_count;
+ m_cv.notify_all();
+ m_cv.wait(lock, [this] { return ((m_all_arrived) || !m_is_active); });
+ }
+
+ void terminate()
+ {
+ {
+ std::unique_lock<std::mutex> lock(m_mutex);
+ m_is_active.store(false);
+ }
+ m_cv.notify_all();
+ }
+
+private:
+ const size_t m_original_count;
+ std::atomic_size_t m_count;
+ std::atomic_bool m_all_arrived;
+
+ std::mutex m_mutex;
+ std::condition_variable m_cv;
+ std::atomic_bool m_is_active;
+};
+
+
+void write_all(std::shared_ptr<ConfiguredNetworkGroup> network_group, InputVStream &input_vstream,
+ std::shared_ptr<SyncObject> sync_object, std::shared_ptr<std::atomic_bool> should_threads_run, hailo_status &status_out)
+{
+ std::vector<uint8_t> buff(input_vstream.get_frame_size());
+
+ auto status = HAILO_UNINITIALIZED;
+ while (true) {
+ if (!(*should_threads_run)) {
+ break;
+ }
+ status = network_group->wait_for_activation(WAIT_FOR_ACTIVATION_TIMEOUT_MS);
+ if (HAILO_TIMEOUT == status) {
+ continue;
+ } else if (HAILO_SUCCESS != status) {
+ std::cerr << "Wait for network group activation failed. status = " << status << std::endl;
+ status_out = status;
+ return;
+ }
+
+ for (size_t i = 0; i < INFER_FRAME_COUNT; i++) {
+ status = input_vstream.write(MemoryView(buff.data(), buff.size()));
+ if (HAILO_SUCCESS != status) {
+ status_out = status;
+ return;
+ }
+ }
+ sync_object->notify_and_wait();
+ }
+ return;
+}
+
+void read_all(std::shared_ptr<ConfiguredNetworkGroup> network_group, OutputVStream &output_vstream,
+ std::shared_ptr<SyncObject> sync_object, std::shared_ptr<std::atomic_bool> should_threads_run, hailo_status &status_out)
+{
+ std::vector<uint8_t> buff(output_vstream.get_frame_size());
+
+ auto status = HAILO_UNINITIALIZED;
+ while (true) {
+ if (!(*should_threads_run)) {
+ break;
+ }
+ status = network_group->wait_for_activation(WAIT_FOR_ACTIVATION_TIMEOUT_MS);
+ if (HAILO_TIMEOUT == status) {
+ continue;
+ } else if (HAILO_SUCCESS != status) {
+ std::cerr << "Wait for network group activation failed. status = " << status << std::endl;
+ status_out = status;
+ return;
+ }
+
+ for (size_t i = 0; i < INFER_FRAME_COUNT; i++) {
+ status = output_vstream.read(MemoryView(buff.data(), buff.size()));
+ if (HAILO_SUCCESS != status) {
+ status_out = status;
+ return;
+ }
+ }
+ sync_object->notify_and_wait();
+ }
+ return;
+}
+
+void network_group_thread_main(std::shared_ptr<ConfiguredNetworkGroup> network_group, std::shared_ptr<SyncObject> sync_object,
+ std::shared_ptr<std::atomic_bool> should_threads_run, hailo_status &status_out)
+{
+ // Create VStreams
+ auto vstreams_exp = VStreamsBuilder::create_vstreams(*network_group, QUANTIZED, FORMAT_TYPE);
+ if (!vstreams_exp) {
+ std::cerr << "Failed to create vstreams, status = " << vstreams_exp.status() << std::endl;
+ status_out = vstreams_exp.status();
+ return;
+ }
+
+ // Create send/recv loops
+ std::vector<std::unique_ptr<std::thread>> recv_ths;
+ std::vector<hailo_status> read_results;
+ read_results.reserve(vstreams_exp->second.size());
+ for (auto &vstream : vstreams_exp->second) {
+ read_results.push_back(HAILO_SUCCESS); // Success oriented
+ recv_ths.emplace_back(std::make_unique<std::thread>(read_all,
+ network_group, std::ref(vstream), sync_object, should_threads_run, std::ref(read_results.back())));
+ }
+
+ std::vector<std::unique_ptr<std::thread>> send_ths;
+ std::vector<hailo_status> write_results;
+ write_results.reserve(vstreams_exp->first.size());
+ for (auto &vstream : vstreams_exp->first) {
+ write_results.push_back(HAILO_SUCCESS); // Success oriented
+ send_ths.emplace_back(std::make_unique<std::thread>(write_all,
+ network_group, std::ref(vstream), std::ref(sync_object), should_threads_run, std::ref(write_results.back())));
+ }
+
+ for (auto &send_th : send_ths) {
+ if (send_th->joinable()) {
+ send_th->join();
+ }
+ }
+ for (auto &recv_th : recv_ths) {
+ if (recv_th->joinable()) {
+ recv_th->join();
+ }
+ }
+
+ for (auto &status : read_results) {
+ if (HAILO_SUCCESS != status) {
+ status_out = status;
+ return;
+ }
+ }
+ for (auto &status : write_results) {
+ if (HAILO_SUCCESS != status) {
+ status_out = status;
+ return;
+ }
+ }
+ status_out = HAILO_SUCCESS;
+ return;
+}
+
+int main()
+{
+ hailo_vdevice_params_t params;
+ auto status = hailo_init_vdevice_params(¶ms);
+ if (HAILO_SUCCESS != status) {
+ std::cerr << "Failed init vdevice_params, status = " << status << std::endl;
+ return status;
+ }
+
+ params.device_count = DEVICE_COUNT;
+ auto vdevice_exp = VDevice::create(params);
+ if (!vdevice_exp) {
+ std::cerr << "Failed create vdevice, status = " << vdevice_exp.status() << std::endl;
+ return vdevice_exp.status();
+ }
+ auto vdevice = vdevice_exp.release();
+
+ std::vector<std::string> hef_paths = {"hefs/shortcut_net.hef", "hefs/shortcut_net.hef"};
+ std::vector<std::shared_ptr<ConfiguredNetworkGroup>> configured_network_groups;
+
+ for (const auto &path : hef_paths) {
+ auto hef_exp = Hef::create(path);
+ if (!hef_exp) {
+ std::cerr << "Failed to create hef: " << path << ", status = " << hef_exp.status() << std::endl;
+ return hef_exp.status();
+ }
+ auto hef = hef_exp.release();
+
+ auto added_network_groups = vdevice->configure(hef);
+ if (!added_network_groups) {
+ std::cerr << "Failed to configure vdevice, status = " << added_network_groups.status() << std::endl;
+ return added_network_groups.status();
+ }
+ configured_network_groups.insert(configured_network_groups.end(), added_network_groups->begin(), added_network_groups->end());
+ }
+
+ auto should_threads_run = std::make_shared<std::atomic_bool>(true);
+
+ std::vector<std::shared_ptr<SyncObject>> sync_objects;
+ sync_objects.reserve(configured_network_groups.size());
+ std::vector<hailo_status> threads_results;
+ threads_results.reserve(configured_network_groups.size());
+ std::vector<std::unique_ptr<std::thread>> network_group_threads;
+ network_group_threads.reserve(configured_network_groups.size());
+
+ for (auto network_group : configured_network_groups) {
+ threads_results.push_back(HAILO_UNINITIALIZED);
+ auto vstream_infos = network_group->get_all_vstream_infos();
+ if (!vstream_infos) {
+ std::cerr << "Failed to get vstream infos, status = " << vstream_infos.status() << std::endl;
+ return vstream_infos.status();
+ }
+ sync_objects.emplace_back((std::make_shared<SyncObject>(vstream_infos->size())));
+ network_group_threads.emplace_back(std::make_unique<std::thread>(network_group_thread_main,
+ network_group, sync_objects.back(), should_threads_run, std::ref(threads_results.back())));
+ }
+
+ for (size_t i = 0; i < RUN_COUNT; i++) {
+ for (size_t network_group_idx = 0; network_group_idx < configured_network_groups.size(); network_group_idx++) {
+ auto activated_network_group_exp = configured_network_groups[network_group_idx]->activate();
+ if (!activated_network_group_exp) {
+ std::cerr << "Failed to activate network group, status = " << activated_network_group_exp.status() << std::endl;
+ return activated_network_group_exp.status();
+ }
+ sync_objects[network_group_idx]->wait_all(activated_network_group_exp.release());
+ }
+ }
+
+ *should_threads_run = false;
+ for (auto &sync_object : sync_objects) {
+ sync_object->terminate();
+ }
+
+ for (auto &th : network_group_threads) {
+ if (th->joinable()) {
+ th->join();
+ }
+ }
+
+ for (auto &thread_status : threads_results) {
+ if (HAILO_SUCCESS != thread_status) {
+ std::cerr << "Inference failed, status = " << thread_status << std::endl;
+ return thread_status;
+ }
+ }
+
+ std::cout << "Inference finished successfully" << std::endl;
+ return HAILO_SUCCESS;
+}
\ No newline at end of file
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
**/
/**
- * @ file vstreams_example
+ * @file vstreams_example
* This example demonstrates using virtual streams over c++
**/
constexpr hailo_format_type_t FORMAT_TYPE = HAILO_FORMAT_TYPE_AUTO;
constexpr size_t MAX_LAYER_EDGES = 16;
-
-using hailort::VDevice;
-using hailort::Hef;
-using hailort::Expected;
-using hailort::make_unexpected;
-using hailort::ConfiguredNetworkGroup;
-using hailort::VStreamsBuilder;
-using hailort::InputVStream;
-using hailort::OutputVStream;
-using hailort::MemoryView;
-
+using namespace hailort;
Expected<std::shared_ptr<ConfiguredNetworkGroup>> configure_network_group(VDevice &vdevice)
{
MULTI_NETWORK_VARIABLE_BATCH_SIZE = 8;
IS_NMS_MULTI_CONTEXT = 9;
OFFLOAD_ARGMAX = 10;
+ HW_PADDING = 11;
+ PRELIMINARY_RUN_ASAP = 12;
UNUSED = 0XFFFF;
}
repeated ProtoHEFResourceIndices buffer_indices = 13;
bool host_argmax = 14;
+ uint32 max_shmifo_size = 15;
}
// Additional information for specific layer types
/**
* Start performing a long power measurement.
*
- * @param[in] delay_milliseconds Amount of time between each measurement interval.
+ * @param[in] unused Unused parameter.
* This time period is sleep time of the core.
* @param[in] averaging_factor Number of samples per time period, sensor configuration value.
* @param[in] sampling_period Related conversion time, sensor configuration value.
* Note that the average calculated by the firmware is “average of averages”,
* because it averages values that have already been averaged by the sensor.
* @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error.
+ * @note This function is deprecated. One should use 'Device::start_power_measurement(hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period)'
*/
- hailo_status start_power_measurement(uint32_t delay_milliseconds, hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period);
+ hailo_status start_power_measurement(uint32_t unused, hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period);
/**
* Set parameters for long power measurement.
* @param[in] measurement_type The type of the measurement. Choosing ::HAILO_POWER_MEASUREMENT_TYPES__AUTO
* will select the default value according to the supported features.
* @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error.
+ * @note This function is deprecated. One should use 'Device::set_power_measurement(hailo_measurement_buffer_index_t buffer_index, hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type)'
*/
hailo_status set_power_measurement(uint32_t index, hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type);
* @param[in] index Index of the buffer on the firmware the data would be saved at.
* @param[in] should_clear Flag indicating if the results saved at the firmware will be deleted after reading.
* @return Upon success, returns @a hailo_power_measurement_data_t. Measured units are determined due to ::hailo_power_measurement_types_t
- * passed to ::hailo_set_power_measurement. Otherwise, returns a ::hailo_status error.
+ * passed to 'Device::set_power_measurement'. Otherwise, returns a ::hailo_status error.
+ * @note This function is deprecated. One should use "Device::get_power_measurement(hailo_measurement_buffer_index_t buffer_index, bool should_clear)'
*/
Expected<hailo_power_measurement_data_t> get_power_measurement(uint32_t index, bool should_clear);
+ /**
+ * Start performing a long power measurement.
+ *
+ * @param[in] averaging_factor Number of samples per time period, sensor configuration value.
+ * @param[in] sampling_period Related conversion time, sensor configuration value.
+ * The sensor samples the power every sampling_period {ms} and averages every
+ * averaging_factor samples. The sensor provides a new value every: 2 * sampling_period * averaging_factor {ms}.
+ * The firmware wakes up every interval_milliseconds {ms} and checks the sensor.
+ * If there is a new value to read from the sensor, the firmware reads it.
+ * Note that the average calculated by the firmware is “average of averages”,
+ * because it averages values that have already been averaged by the sensor.
+ * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error.
+ */
+ hailo_status start_power_measurement(hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period);
+
+
+ /**
+ * Set parameters for long power measurement.
+ *
+ * @param[in] buffer_index A ::hailo_measurement_buffer_index_t represents the buffer on the firmware the data would be saved at.
+ * Should match the one passed to 'Device::get_power_measurement'.
+ * @param[in] dvm Which DVM will be measured. Default (::HAILO_DVM_OPTIONS_AUTO) will be different according to the board: <br>
+ * - Default (::HAILO_DVM_OPTIONS_AUTO) for EVB is an approximation to the total power consumption of the chip in PCIe setups.
+ * It sums ::HAILO_DVM_OPTIONS_VDD_CORE, ::HAILO_DVM_OPTIONS_MIPI_AVDD and ::HAILO_DVM_OPTIONS_AVDD_H.
+ * Only ::HAILO_POWER_MEASUREMENT_TYPES__POWER can measured with this option.
+ * - Default (::HAILO_DVM_OPTIONS_AUTO) for platforms supporting current monitoring (such as M.2 and mPCIe): OVERCURRENT_PROTECTION.
+ * @param[in] measurement_type The type of the measurement. Choosing ::HAILO_POWER_MEASUREMENT_TYPES__AUTO
+ * will select the default value according to the supported features.
+ * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error.
+ */
+ hailo_status set_power_measurement(hailo_measurement_buffer_index_t buffer_index, hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type);
+
+ /**
+ * Read measured power from a long power measurement
+ *
+ * @param[in] buffer_index A ::hailo_measurement_buffer_index_t represents the buffer on the firmware the data would be saved at.
+ * Should match the one passed to 'Device::set_power_measurement'.
+ * @param[in] should_clear Flag indicating if the results saved at the firmware will be deleted after reading.
+ * @return Upon success, returns @a hailo_power_measurement_data_t. Measured units are determined due to ::hailo_power_measurement_types_t
+ * passed to 'Device::set_power_measurement'. Otherwise, returns a ::hailo_status error.
+ */
+ Expected<hailo_power_measurement_data_t> get_power_measurement(hailo_measurement_buffer_index_t buffer_index, bool should_clear);
+
/**
* Stop performing a long power measurement.
*
* @param[in] opaque User specific data.
* @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error.
*/
- virtual hailo_status set_notification_callback(NotificationCallback func, hailo_notification_id_t notification_id,
+ virtual hailo_status set_notification_callback(const NotificationCallback &func, hailo_notification_id_t notification_id,
void *opaque) = 0;
/**
Expected<std::vector<uint8_t>> get_number_of_contexts_per_network_group();
Expected<Buffer> download_context_action_list(uint8_t context_index, uint32_t *base_address,
uint32_t *batch_counter, uint16_t max_size = 10000);
+ // The batch configured is reset between network groups
+ hailo_status set_context_action_list_timestamp_batch(uint16_t batch_index);
virtual ~Device() = default;
Device(const Device &) = delete;
#include <poll.h>
#endif
+#if defined(__QNX__)
+#include <atomic>
+#include <mutex>
+
+// Forward declare neosmart::neosmart_event_t_
+namespace neosmart {
+ struct neosmart_event_t_;
+}
+#endif // defined (__QNX__)
+
namespace hailort
{
+// underlying_waitable_handle_t
+#if defined(_MSC_VER) || defined(__linux__)
+ typedef underlying_handle_t underlying_waitable_handle_t;
+#elif defined(__QNX__)
+ typedef neosmart::neosmart_event_t_* underlying_waitable_handle_t;
+#else
+ #error "Unsupported Platform"
+#endif
+
+
class Waitable;
using WaitablePtr = std::shared_ptr<Waitable>;
using WaitablePtrList = std::vector<WaitablePtr>;
class HAILORTAPI Waitable
{
public:
- explicit Waitable(underlying_handle_t handle);
+ explicit Waitable(underlying_waitable_handle_t handle);
virtual ~Waitable();
Waitable(Waitable&& other);
virtual hailo_status wait(std::chrono::milliseconds timeout) = 0;
virtual hailo_status signal() = 0;
virtual bool is_auto_reset() = 0;
- underlying_handle_t get_underlying_handle();
+ underlying_waitable_handle_t get_underlying_handle();
+#if defined(__QNX__)
+ virtual void post_wait() = 0;
+#endif // defined (__QNX__)
static constexpr auto INIFINITE_TIMEOUT() { return std::chrono::milliseconds(HAILO_INFINITE); }
protected:
- #if defined(_MSC_VER)
- static hailo_status wait_for_single_object(underlying_handle_t handle, std::chrono::milliseconds timeout);
+ #if defined(_MSC_VER) || defined(__QNX__)
+ static hailo_status wait_for_single_object(underlying_waitable_handle_t handle, std::chrono::milliseconds timeout);
#else
// Waits on the fd until the waitable is signaled
- static hailo_status eventfd_poll(underlying_handle_t fd, std::chrono::milliseconds timeout);
+ static hailo_status eventfd_poll(underlying_waitable_handle_t fd, std::chrono::milliseconds timeout);
// Expected to be called after eventfd_poll returns HAILO_SUCCESS
- static hailo_status eventfd_read(underlying_handle_t fd);
- static hailo_status eventfd_write(underlying_handle_t fd);
+ static hailo_status eventfd_read(underlying_waitable_handle_t fd);
+ static hailo_status eventfd_write(underlying_waitable_handle_t fd);
#endif
- underlying_handle_t m_handle;
+ underlying_waitable_handle_t m_handle;
};
class Event;
virtual hailo_status signal() override;
virtual bool is_auto_reset() override;
hailo_status reset();
+#if defined(__QNX__)
+ virtual void post_wait() override;
+#endif // defined (__QNX__)
private:
- static underlying_handle_t open_event_handle(const State& initial_state);
+ static underlying_waitable_handle_t open_event_handle(const State& initial_state);
};
class Semaphore;
virtual hailo_status wait(std::chrono::milliseconds timeout) override;
virtual hailo_status signal() override;
virtual bool is_auto_reset() override;
+#if defined(__QNX__)
+ Semaphore(underlying_waitable_handle_t handle, uint32_t initial_count);
+ Semaphore(Semaphore&& other);
+
+ virtual void post_wait() override;
+#endif // defined (__QNX__)
private:
- static underlying_handle_t open_semaphore_handle(uint32_t initial_count);
+ static underlying_waitable_handle_t open_semaphore_handle(uint32_t initial_count);
+#if defined (__QNX__)
+ std::atomic<unsigned int> m_count;
+ std::mutex m_sem_mutex;
+#endif // defined(__QNX__)
};
} /* namespace hailort */
{
public:
/**
- * Expected<T> can access Expected<U>'s private members (needed for implicit upcasting)
+ * Expected<T> can access Expected\<U\>'s private members (needed for implicit upcasting)
*/
template<class U>
friend class Expected;
* Copy constructor
*/
explicit Expected(const Expected<T> &other) :
- m_value(other.m_value),
m_status(other.m_status)
- {}
+ {
+ if (other.has_value()) {
+ construct(&m_value, other.m_value);
+ }
+ }
/**
* Copy constructor for implicit upcasting
*/
template <typename U>
Expected(const Expected<U>& other) :
- m_value(other.m_value),
m_status(other.m_status)
- {}
+ {
+ if (other.has_value()) {
+ construct(&m_value, other.m_value);
+ }
+ }
/**
* Move constructor
*
* Construct a new Expected<T> where:
- * - other.m_value moved to this.m_value.
- * - other.m_status moved to this.m_status, and other.m_status is set to HAILO_UNINITIALIZED.
+ * - other.m_status moved to this.m_status.
+ * - other.m_value moved to this.m_value if other.m_value exists.
+ *
+ * If other had value before the move, it will still have the value that was moved (so the value object is valid but
+ * in an unspecified state).
*/
Expected(Expected<T> &&other) :
- m_value(std::move(other.m_value)),
- m_status(std::exchange(other.m_status, HAILO_UNINITIALIZED))
- {}
+ m_status(other.m_status)
+ {
+ if (other.has_value()) {
+ construct(&m_value, std::move(other.m_value));
+ }
+ }
/**
* Construct a new Expected<T> from T& where:
}
private:
+ template<typename... Args>
+ static void construct(T *value, Args &&...args)
+ {
+ new ((void*)value) T(std::forward<Args>(args)...);
+ }
+
union {
T m_value;
};
HAILO_AVERAGE_FACTOR_MAX_ENUM = HAILO_MAX_ENUM
} hailo_averaging_factor_t;
+/** Enum that represents buffers on the device for power measurements storing */
+typedef enum hailo_measurement_buffer_index_e {
+ HAILO_MEASUREMENT_BUFFER_INDEX_0 = 0,
+ HAILO_MEASUREMENT_BUFFER_INDEX_1,
+ HAILO_MEASUREMENT_BUFFER_INDEX_2,
+ HAILO_MEASUREMENT_BUFFER_INDEX_3,
+
+ /** Max enum value to maintain ABI Integrity */
+ HAILO_MEASUREMENT_BUFFER_INDEX_MAX_ENUM = HAILO_MAX_ENUM
+} hailo_measurement_buffer_index_t;
+
/** Data of the power measurement samples */
typedef struct {
float32_t average_value;
uint32_t func;
} hailo_pcie_device_info_t;
+/** Scheduler algorithm */
+typedef enum hailo_scheduling_algorithm_e {
+ /** Scheduling disabled */
+ HAILO_SCHEDULING_ALGORITHM_NONE = 0,
+ /** Round Robin */
+ HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN,
+
+ /** Max enum value to maintain ABI Integrity */
+ HAILO_SCHEDULING_ALGORITHM_MAX_ENUM = HAILO_MAX_ENUM
+} hailo_scheduling_algorithm_t;
+
/** Virtual device parameters */
typedef struct {
/** Requested number of physical devices. if @a device_infos is not NULL, represents the number of ::hailo_pcie_device_info_t in @a device_infos */
uint32_t device_count;
/** Specific physical devices information to create the vdevice from. If NULL, the vdevice will try to occupy devices from the available pool */
hailo_pcie_device_info_t *device_infos;
+ /** The scheduling algorithm to use for network group scheduling */
+ hailo_scheduling_algorithm_t scheduling_algorithm;
} hailo_vdevice_params_t;
/** Device architecture */
/** Hailo stream parameters */
typedef struct {
- union {
- #ifndef _MSC_VER
- // Windows combaseapi.h uses `inteface` as a keyword
- hailo_stream_interface_t interface DEPRECATED("interface is deprecated. One should use stream_interface instead.");
- #endif
- hailo_stream_interface_t stream_interface;
- };
-
+ hailo_stream_interface_t stream_interface;
hailo_stream_direction_t direction;
union {
hailo_pcie_input_stream_params_t pcie_input_params;
char name[HAILO_MAX_NETWORK_NAME_SIZE];
} hailo_network_info_t;
-/** Hailo device ID string - BDF for PCIe devices, MAC address for Ethernet devices, "Core" for core devices. **/
+/** Hailo device ID string - BDF for PCIe devices, IP address for Ethernet devices, "Core" for core devices. **/
typedef struct {
char id[HAILO_MAX_DEVICE_ID_LENGTH];
} hailo_device_id_t;
/**
* Get device id which is the identification string of the device. BDF for PCIe devices,
- * MAC address for Ethernet devices, "Core" for core devices.
+ * IP address for Ethernet devices, "Core" for core devices.
*
* @param[in] device A ::hailo_device object.
* @param[out] id The returned device id.
* Start performing a long power measurement.
*
* @param[in] device A ::hailo_device object.
- * @param[in] delay_milliseconds Amount of time between each measurement interval.
- * This time period is sleep time of the core.
* @param[in] averaging_factor Number of samples per time period, sensor configuration value.
* @param[in] sampling_period Related conversion time, sensor configuration value.
* The sensor samples the power every sampling_period {ms} and averages every
* because it averages values that have already been averaged by the sensor.
* @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error.
*/
-HAILORTAPI hailo_status hailo_start_power_measurement(hailo_device device, uint32_t delay_milliseconds,
+HAILORTAPI hailo_status hailo_start_power_measurement(hailo_device device,
hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period);
/**
* Set parameters for long power measurement.
*
* @param[in] device A ::hailo_device object.
- * @param[in] index Index of the buffer on the firmware the data would be saved at.
+ * @param[in] buffer_index A ::hailo_measurement_buffer_index_t represents the buffer on the firmware the data would be saved at.
+ * Should match the one passed to ::hailo_get_power_measurement.
* @param[in] dvm Which DVM will be measured. Default (::HAILO_DVM_OPTIONS_AUTO) will be different according to the board: <br>
* - Default (::HAILO_DVM_OPTIONS_AUTO) for EVB is an approximation to the total power consumption of the chip in PCIe setups.
* It sums ::HAILO_DVM_OPTIONS_VDD_CORE, ::HAILO_DVM_OPTIONS_MIPI_AVDD and ::HAILO_DVM_OPTIONS_AVDD_H.
* will select the default value according to the supported features.
* @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error.
*/
-HAILORTAPI hailo_status hailo_set_power_measurement(hailo_device device, uint32_t index,
+HAILORTAPI hailo_status hailo_set_power_measurement(hailo_device device, hailo_measurement_buffer_index_t buffer_index,
hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type);
/**
* Read measured power from a long power measurement
*
* @param[in] device A ::hailo_device object.
- * @param[in] index Index of the buffer on the firmware the data would be saved at.
+ * @param[in] buffer_index A ::hailo_measurement_buffer_index_t represents the buffer on the firmware the data would be saved at.
+ * Should match the one passed to ::hailo_set_power_measurement.
* @param[in] should_clear Flag indicating if the results saved at the firmware will be deleted after reading.
* @param[out] measurement_data The measurement data, ::hailo_power_measurement_data_t. Measured units are
* determined due to ::hailo_power_measurement_types_t passed to ::hailo_set_power_measurement
* @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error.
*/
-HAILORTAPI hailo_status hailo_get_power_measurement(hailo_device device, uint32_t index, bool should_clear,
+HAILORTAPI hailo_status hailo_get_power_measurement(hailo_device device, hailo_measurement_buffer_index_t buffer_index, bool should_clear,
hailo_power_measurement_data_t *measurement_data);
/**
HAILORTAPI hailo_status hailo_get_latency_measurement(hailo_configured_network_group configured_network_group,
const char *network_name, hailo_latency_measurement_result_t *result);
+/**
+ * Sets the maximum time period that may pass before getting run time from the scheduler,
+ * even without reaching the minimum required send requests (e.g. threshold - see hailo_set_scheduler_threshold()),
+ * as long as at least one send request has been sent.
+ * This time period is measured since the last time the scheduler gave this network group run time.
+ *
+ * @param[in] configured_network_group NetworkGroup for which to set the scheduler timeout.
+ * @param[in] timeout_ms Timeout in milliseconds.
+ * @param[in] network_name Network name for which to set the timeout.
+ * If NULL is passed, the timeout will be set for all the networks in the network group.
+ * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error.
+ * @note Using this function is only allowed when scheduling_algorithm is not ::HAILO_SCHEDULING_ALGORITHM_NONE, and before the creation of any vstreams.
+ * @note The default timeout is 0ms.
+ * @note Currently, setting the timeout for a specific network is not supported.
+ */
+HAILORTAPI hailo_status hailo_set_scheduler_timeout(hailo_configured_network_group configured_network_group,
+ uint32_t timeout_ms, const char *network_name);
+
+/**
+ * Sets the minimum number of send requests required before the network is considered ready to get run time from the scheduler.
+ * If at least one send request has been sent, but the threshold is not reached within a set time period (e.g. timeout - see hailo_set_scheduler_timeout()),
+ * the scheduler will consider the network ready regardless.
+ *
+ * @param[in] configured_network_group NetworkGroup for which to set the scheduler threshold.
+ * @param[in] threshold Threshold in number of frames.
+ * @param[in] network_name Network name for which to set the threshold.
+ * If NULL is passed, the threshold will be set for all the networks in the network group.
+ * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error.
+ * @note Using this function is only allowed when scheduling_algorithm is not ::HAILO_SCHEDULING_ALGORITHM_NONE, and before the creation of any vstreams.
+ * @note The default threshold is 1.
+ * @note Currently, setting the threshold for a specific network is not supported.
+ */
+HAILORTAPI hailo_status hailo_set_scheduler_threshold(hailo_configured_network_group configured_network_group,
+ uint32_t threshold, const char *network_name);
+
/** @} */ // end of group_network_group_functions
/** @defgroup group_stream_functions Stream functions
* @{
*/
-/**
- * Returns the network latency (only available if latency measurement was enabled).
- *
- * @param[in] configured_network_group NetworkGroup to get the latency measurement from.
- * @param[out] result Output latency result.
- * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error.
- * @note This function is deprecated. One should use 'hailo_get_latency_measurement()'
- */
-HAILORTAPI hailo_status hailo_get_latency_measurement_from_network_group(hailo_configured_network_group configured_network_group,
- hailo_latency_measurement_result_t *result)
- DEPRECATED("'hailo_get_latency_measurement_from_network_group' is deprecated. One should use 'hailo_get_latency_measurement()'.");
-
-
-typedef hailo_input_transform_context hailo_input_transformer DEPRECATED("hailo_input_transformer is deprecated. One should use hailo_input_transform_context");
-typedef hailo_output_transform_context hailo_output_transformer DEPRECATED("hailo_output_transformer is deprecated. One should use hailo_output_transform_context");
-
-/**
- * Creates an input transformer object. Allocates all necessary buffers used for the transformation (pre-process).
- *
- * @param[in] stream_info - A ::hailo_stream_info_t object
- * @param[in] transform_params - A ::hailo_transform_params_t user transformation parameters.
- * @param[out] transformer - A ::hailo_input_transform_context
- *
- * @return Upon success, returns @a HAILO_SUCCESS. Otherwise, returns an @a hailo_status error.
- *
- * @note To release the transformer, call the ::hailo_release_input_transformer function
- * with the returned ::hailo_input_transform_context.
- *
- */
-HAILORTAPI hailo_status hailo_create_input_transformer(const hailo_stream_info_t *stream_info,
- const hailo_transform_params_t *transform_params, hailo_input_transform_context *transformer)
- DEPRECATED("hailo_create_input_transformer is deprecated. One should use hailo_create_input_transform_context");
-
-/**
- * Releases a transformer object including all allocated buffers.
- *
- * @param[in] transformer - A ::hailo_input_transform_context object.
- *
- * @return Upon success, returns @a HAILO_SUCCESS. Otherwise, returns an @a hailo_status error.
- */
-HAILORTAPI hailo_status hailo_release_input_transformer(hailo_input_transform_context transformer)
- DEPRECATED("hailo_release_input_transformer is deprecated. One should use hailo_release_input_transform_context");
-
-/**
- * Transforms an input frame pointed to by @a src directly to the buffer pointed to by @a dst.
- *
- * @param[in] transformer A ::hailo_input_transform_context.
- * @param[in] src A pointer to a buffer to be transformed.
- * @param[in] src_size The number of bytes to transform. This number must be equal to the input host_frame_size,
- * and less than or equal to the size of @a src buffer.
- * @param[out] dst A pointer to a buffer that receives the transformed data.
- * @param[in] dst_size The number of bytes in @a dst buffer. This number must be equal to the input hw_frame_size,
- * and less than or equal to the size of @a dst buffer.
- * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error.
- * @warning The buffers must not overlap.
- */
-HAILORTAPI hailo_status hailo_transform_frame_by_input_transformer(hailo_input_transform_context transformer,
- const void *src, size_t src_size, void *dst, size_t dst_size)
- DEPRECATED("hailo_transform_frame_by_input_transformer is deprecated. One should use hailo_transform_frame_by_input_transform_context");
-
-/**
- * Creates an output transformer object. Allocates all necessary buffers used for the transformation (post-process).
- *
- * @param[in] stream_info - A ::hailo_stream_info_t object
- * @param[in] transform_params - A ::hailo_transform_params_t user transformation parameters.
- * @param[out] transformer - A ::hailo_output_transform_context
- *
- * @return Upon success, returns @a HAILO_SUCCESS. Otherwise, returns an @a hailo_status error.
- *
- * @note To release the transform_context, call the ::hailo_release_output_transform_context function
- * with the returned ::hailo_output_transform_context.
- *
- */
-HAILORTAPI hailo_status hailo_create_output_transformer(const hailo_stream_info_t *stream_info,
- const hailo_transform_params_t *transform_params, hailo_output_transform_context *transformer)
- DEPRECATED("hailo_create_output_transformer is deprecated. One should use hailo_create_output_transform_context");
-
-/**
- * Releases a transformer object including all allocated buffers.
- *
- * @param[in] transformer - A ::hailo_output_transform_context object.
- *
- * @return Upon success, returns @a HAILO_SUCCESS. Otherwise, returns an @a hailo_status error.
- */
-HAILORTAPI hailo_status hailo_release_output_transformer(hailo_output_transform_context transformer)
- DEPRECATED("hailo_release_output_transformer is deprecated. One should use hailo_release_output_transform_context");
-
-/**
- * Transforms an output frame pointed to by @a src directly to the buffer pointed to by @a dst.
- *
- * @param[in] transformer A ::hailo_output_transform_context.
- * @param[in] src A pointer to a buffer to be transformed.
- * @param[in] src_size The number of bytes to transform. This number must be equal to the output hw_frame_size,
- * and less than or equal to the size of @a src buffer.
- * @param[out] dst A pointer to a buffer that receives the transformed data.
- * @param[in] dst_size The number of bytes in @a dst buffer. This number must be equal to the output host_frame_size,
- * and less than or equal to the size of @a dst buffer.
- * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error.
- * @warning The buffers must not overlap.
- */
-HAILORTAPI hailo_status hailo_transform_frame_by_output_transformer(hailo_output_transform_context transformer,
- const void *src, size_t src_size, void *dst, size_t dst_size)
- DEPRECATED("hailo_transform_frame_by_output_transformer is deprecated. One should use hailo_transform_frame_by_output_transform_context");;
-
/** @} */ // end of group_deprecated_functions_and_defines
static const uint32_t MAX_DEFUSED_LAYER_COUNT = 9;
static const size_t HW_DATA_ALIGNMENT = 8;
static const uint64_t NMS_DELIMITER = 0xFFFFFFFFFFFFFFFF;
+ static const uint64_t NMS_DUMMY_DELIMITER = 0xFFFFFFFFFFFFFFFE;
static const uint32_t MUX_INFO_COUNT = 32;
static const uint32_t MAX_MUX_PREDECESSORS = 4;
static const uint16_t ETH_INPUT_BASE_PORT = 32401;
ActivatedNetworkGroup &operator=(ActivatedNetworkGroup &&other) = delete;
ActivatedNetworkGroup(ActivatedNetworkGroup &&other) noexcept = default;
+ /**
+ * @return The network group name.
+ */
+ virtual const std::string &get_network_group_name() const = 0;
+
virtual Expected<Buffer> get_intermediate_buffer(const IntermediateBufferKey &key) = 0;
/**
* @return Upon success, returns Expected of a pointer to ActivatedNetworkGroup object.
* Otherwise, returns Unexpected of ::hailo_status error.
*/
- virtual Expected<std::unique_ptr<ActivatedNetworkGroup>> activate(
- const hailo_activate_network_group_params_t &network_group_params) = 0;
+ virtual Expected<std::unique_ptr<ActivatedNetworkGroup>> activate(const hailo_activate_network_group_params_t &network_group_params) = 0;
/**
* Block until network group is activated, or until timeout is passed.
*/
virtual Expected<std::vector<hailo_vstream_info_t>> get_all_vstream_infos(const std::string &network_name="") const = 0;
+ /**
+ * Sets the maximum time period that may pass before getting run time from the scheduler,
+ * even without reaching the minimum required send requests (e.g. threshold - see set_scheduler_threshold()),
+ * as long as at least one send request has been sent.
+ * This time period is measured since the last time the scheduler gave this network group run time.
+ *
+ * @param[in] timeout Timeout in milliseconds.
+ * @param[in] network_name Network name for which to set the timeout.
+ * If not passed, the timeout will be set for all the networks in the network group.
+ * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error.
+ * @note Using this function is only allowed when scheduling_algorithm is not ::HAILO_SCHEDULING_ALGORITHM_NONE, and before the creation of any vstreams.
+ * @note The default timeout is 0ms.
+ * @note Currently, setting the timeout for a specific network is not supported.
+ */
+ virtual hailo_status set_scheduler_timeout(const std::chrono::milliseconds &timeout, const std::string &network_name="") = 0;
+
+ /**
+ * Sets the minimum number of send requests required before the network is considered ready to get run time from the scheduler.
+ * If at least one send request has been sent, but the threshold is not reached within a set time period (e.g. timeout - see hailo_set_scheduler_timeout()),
+ * the scheduler will consider the network ready regardless.
+ *
+ * @param[in] threshold Threshold in number of frames.
+ * @param[in] network_name Network name for which to set the threshold.
+ * If not passed, the threshold will be set for all the networks in the network group.
+ * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error.
+ * @note Using this function is only allowed when scheduling_algorithm is not ::HAILO_SCHEDULING_ALGORITHM_NONE, and before the creation of any vstreams.
+ * @note The default threshold is 1.
+ * @note Currently, setting the threshold for a specific network is not supported.
+ */
+ virtual hailo_status set_scheduler_threshold(uint32_t threshold, const std::string &network_name="") = 0;
+
virtual AccumulatorPtr get_activation_time_accumulator() const = 0;
virtual AccumulatorPtr get_deactivation_time_accumulator() const = 0;
protected:
ConfiguredNetworkGroup() = default;
+ virtual Expected<std::unique_ptr<ActivatedNetworkGroup>> activate_internal(
+ const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) = 0;
+
private:
friend class ActivatedNetworkGroup;
};
// underlying_handle_t
#ifndef underlying_handle_t
#if defined(_MSC_VER)
-typedef HANDLE underlying_handle_t;
+typedef HANDLE underlying_handle_t;
+#elif defined(__linux__) || defined(__QNX__)
+typedef int underlying_handle_t;
#else
-typedef int underlying_handle_t;
+#error "Unsupported Platform"
#endif
#endif
#define _HAILO_QUANTIZATION_HPP_
#include "hailo/hailort.h"
+#include "hailo/hailort_common.hpp"
#include <math.h>
#include <fenv.h>
*/
virtual EventPtr &get_network_group_activated_event() = 0;
+ /**
+ * @returns whether the stream is managed by a network group scheduler.
+ */
+ virtual bool is_scheduled() = 0;
+
/**
* Writes the entire buffer to the stream without transformations
*
// Note: Implement sync_write_all_raw_buffer_no_transform_impl for the actual stream interaction in sub classes
virtual hailo_status sync_write_all_raw_buffer_no_transform_impl(void *buffer, size_t offset, size_t size) = 0;
- virtual hailo_status activate_stream() = 0;
+ virtual hailo_status activate_stream(uint16_t dynamic_batch_size) = 0;
virtual hailo_status deactivate_stream() = 0;
virtual Expected<size_t> sync_write_raw_buffer(const MemoryView &buffer) = 0;
* @returns a pointer for network group activated event.
*/
virtual EventPtr &get_network_group_activated_event() = 0;
+
+ /**
+ * @returns whether the stream is managed by a network group scheduler.
+ */
+ virtual bool is_scheduled() = 0;
/**
* @returns the stream's info.
OutputStream() = default;
OutputStream(OutputStream&&);
- virtual hailo_status activate_stream() = 0;
+ virtual hailo_status activate_stream(uint16_t dynamic_batch_size) = 0;
virtual hailo_status deactivate_stream() = 0;
virtual hailo_status read_all(MemoryView &buffer) = 0;
Buffer m_transpose_buffer;
};
-typedef InputTransformContext InputTransformer DEPRECATED("InputTransformer is deprecated. One should use InputTransformContext");
-
/*! Object used for output stream transformation*/
class HAILORTAPI OutputTransformContext
{
const bool m_should_reorder;
};
-typedef OutputTransformContext OutputTransformer DEPRECATED("OutputTransformer is deprecated. One should use OutputTransformContext");
-
/*! Object used to demux muxed stream */
class HAILORTAPI OutputDemuxer {
public:
find_package(Threads REQUIRED)
+include(GNUInstallDirs)
+include(CMakePackageConfigHelpers)
include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/common_compiler_options.cmake)
FUNCTION(relative_to_absolute_paths output)
context_switch/vdma_config_network_group.cpp
context_switch/vdma_config_activated_network_group.cpp
context_switch/network_group.cpp
+ context_switch/network_group_wrapper.cpp
context_switch/resource_manager.cpp
+ context_switch/pipeline_multiplexer.cpp
intermediate_buffer.cpp
+ config_buffer.cpp
d2h_events_parser.cpp
mipi_stream.cpp
hlpcie.cpp
vdma_channel.cpp
- vdma_buffer.cpp
vdma_descriptor_list.cpp
vdma_device.cpp
vdma_stream.cpp
+ vdma/mapped_buffer.cpp
+ vdma/sg_buffer.cpp
+ vdma/continuous_buffer.cpp
+
pcie_device.cpp
pcie_stream.cpp
vstream.cpp
inference_pipeline.cpp
+
+ network_group_scheduler.cpp
)
set(common_dir "${PROJECT_SOURCE_DIR}/common/src")
target_link_libraries(libhailort PRIVATE hef_proto)
target_link_libraries(libhailort PRIVATE spdlog::spdlog)
target_link_libraries(libhailort PRIVATE readerwriterqueue)
+target_link_libraries(libhailort PRIVATE microprofile)
+if(CMAKE_SYSTEM_NAME STREQUAL QNX)
+ target_link_libraries(libhailort PRIVATE pevents pci)
+endif()
set(HAILORT_PUBLIC_HEADERS
${HAILORT_INC_DIR}/hailo/hailort.h
)
install(TARGETS libhailort
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
- CONFIGURATIONS Release
- PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/hailo"
- CONFIGURATIONS Release)
+ EXPORT HailoRTTargets
+ CONFIGURATIONS Release
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/hailo"
+ INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+)
+
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ install(CODE "execute_process(COMMAND ldconfig)")
+endif()
+
+# Export libhailort
+set(CMAKE_SCRIPTS_DIR ${CMAKE_CURRENT_BINARY_DIR})
+configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
+ "${CMAKE_SCRIPTS_DIR}/HailoRTConfig.cmake"
+ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/HailoRT
+)
+write_basic_package_version_file(
+ "${CMAKE_SCRIPTS_DIR}/HailoRTConfigVersion.cmake"
+ VERSION "${HAILORT_MAJOR_VERSION}.${HAILORT_MINOR_VERSION}.${HAILORT_REVISION_VERSION}"
+ COMPATIBILITY ExactVersion
+)
+
+# Support builds without installation
+set(HailoRT_DIR "${CMAKE_SCRIPTS_DIR}" PARENT_SCOPE)
+
+# Package installation
+install(FILES
+ "${CMAKE_SCRIPTS_DIR}/HailoRTConfig.cmake"
+ "${CMAKE_SCRIPTS_DIR}/HailoRTConfigVersion.cmake"
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/HailoRT
+ COMPONENT libhailort
+)
+install(EXPORT HailoRTTargets
+ FILE HailoRTTargets.cmake
+ NAMESPACE HailoRT::
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/HailoRT
+ COMPONENT libhailort
+)
--- /dev/null
+@PACKAGE_INIT@
+
+if(TARGET libhailort)
+ if(${HailoRT_FIND_VERSION} VERSION_EQUAL "${HAILORT_MAJOR_VERSION}.${HAILORT_MINOR_VERSION}.${HAILORT_REVISION_VERSION}")
+ add_library(HailoRT::libhailort ALIAS libhailort)
+ endif()
+else()
+ include("${CMAKE_CURRENT_LIST_DIR}/HailoRTTargets.cmake")
+ check_required_components(HailoRT)
+endif()
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file config_buffer.cpp
+ * @brief Manages configuration vdma buffer. The configuration buffer contains nn-configurations in a specific
+ * hw format (ccw).
+ */
+
+#include "config_buffer.hpp"
+#include "vdma/sg_buffer.hpp"
+#include "vdma/continuous_buffer.hpp"
+
+#include <numeric>
+
+namespace hailort {
+
+Expected<ConfigBuffer> ConfigBuffer::create(HailoRTDriver &driver, uint8_t channel_index,
+ const std::vector<uint32_t> &cfg_sizes)
+{
+ const auto buffer_size = std::accumulate(cfg_sizes.begin(), cfg_sizes.end(), 0);
+
+ auto buffer_ptr = should_use_ccb(driver) ?
+ create_ccb_buffer(driver, buffer_size) :
+ create_sg_buffer(driver, channel_index, cfg_sizes);
+ CHECK_EXPECTED(buffer_ptr);
+
+ return ConfigBuffer(buffer_ptr.release(), buffer_size);
+}
+
+ConfigBuffer::ConfigBuffer(std::unique_ptr<vdma::VdmaBuffer> &&buffer,
+ size_t total_buffer_size)
+ : m_buffer(std::move(buffer)),
+ m_total_buffer_size(total_buffer_size), m_acc_buffer_offset(0), m_acc_desc_count(0),
+ m_current_buffer_size(0)
+{}
+
+Expected<uint32_t> ConfigBuffer::program_descriptors()
+{
+ auto descriptors_count =
+ m_buffer->program_descriptors(m_acc_buffer_offset, VdmaInterruptsDomain::NONE, VdmaInterruptsDomain::DEVICE,
+ m_acc_desc_count, false);
+ CHECK_EXPECTED(descriptors_count);
+
+ m_acc_desc_count += descriptors_count.value();
+ m_acc_buffer_offset = 0;
+
+ return descriptors_count;
+}
+
+hailo_status ConfigBuffer::write(const void *data, size_t data_size)
+{
+ size_t total_offset = (m_acc_desc_count * m_buffer->desc_page_size()) + m_acc_buffer_offset;
+ auto status = m_buffer->write(data, data_size, total_offset);
+ CHECK_SUCCESS(status);
+
+ m_acc_buffer_offset += data_size;
+ m_current_buffer_size += data_size;
+ return HAILO_SUCCESS;
+}
+
+size_t ConfigBuffer::get_total_cfg_size()
+{
+ return m_total_buffer_size;
+}
+
+vdma::VdmaBuffer::Type ConfigBuffer::buffer_type() const
+{
+ return m_buffer->type();
+}
+
+size_t ConfigBuffer::get_current_buffer_size()
+{
+ return m_current_buffer_size;
+}
+
+uint16_t ConfigBuffer::desc_page_size() const
+{
+ return m_buffer->desc_page_size();
+}
+
+uint64_t ConfigBuffer::dma_address() const
+{
+ return m_buffer->dma_address();
+}
+
+uint32_t ConfigBuffer::total_desc_count() const
+{
+ return m_buffer->descs_count();
+}
+
+uint32_t ConfigBuffer::acc_desc_count() const
+{
+ return m_acc_desc_count;
+}
+
+Expected<std::unique_ptr<vdma::VdmaBuffer>> ConfigBuffer::create_sg_buffer(HailoRTDriver &driver,
+ uint8_t channel_index, const std::vector<uint32_t> &cfg_sizes)
+{
+ auto desc_sizes_pair = VdmaDescriptorList::get_desc_buffer_sizes_for_multiple_transfers(driver, 1, cfg_sizes);
+ CHECK_EXPECTED(desc_sizes_pair);
+
+ auto page_size = desc_sizes_pair->first;
+ auto descs_count = desc_sizes_pair->second;
+
+ auto buffer = vdma::SgBuffer::create(driver, descs_count, page_size, HailoRTDriver::DmaDirection::H2D,
+ channel_index);
+ CHECK_EXPECTED(buffer);
+
+ auto buffer_ptr = make_unique_nothrow<vdma::SgBuffer>(buffer.release());
+ CHECK_NOT_NULL_AS_EXPECTED(buffer_ptr, HAILO_OUT_OF_HOST_MEMORY);
+
+ return std::unique_ptr<vdma::VdmaBuffer>(std::move(buffer_ptr));
+}
+
+Expected<std::unique_ptr<vdma::VdmaBuffer>> ConfigBuffer::create_ccb_buffer(HailoRTDriver &driver,
+ uint32_t buffer_size)
+{
+ buffer_size = vdma::ContinuousBuffer::get_buffer_size(buffer_size);
+ auto buffer = vdma::ContinuousBuffer::create(buffer_size, driver);
+ CHECK_EXPECTED(buffer);
+
+ auto buffer_ptr = make_unique_nothrow<vdma::ContinuousBuffer>(buffer.release());
+ CHECK_NOT_NULL_AS_EXPECTED(buffer_ptr, HAILO_OUT_OF_HOST_MEMORY);
+
+ return std::unique_ptr<vdma::VdmaBuffer>(std::move(buffer_ptr));
+}
+
+bool ConfigBuffer::should_use_ccb(HailoRTDriver &driver)
+{
+ switch (driver.dma_type()) {
+ case HailoRTDriver::DmaType::PCIE:
+ return false;
+ case HailoRTDriver::DmaType::DRAM:
+ return true;
+ default:
+ assert(true);
+ return false;
+ }
+}
+
+} /* hailort */
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file config_buffer.hpp
+ * @brief Manages configuration vdma buffer. The configuration buffer contains nn-configurations in a specific
+ * hw format (ccw).
+ */
+
+#ifndef _HAILO_CONFIG_BUFFER_HPP_
+#define _HAILO_CONFIG_BUFFER_HPP_
+
+#include "vdma/vdma_buffer.hpp"
+
+namespace hailort {
+
+
+class ConfigBuffer final
+{
+public:
+ static Expected<ConfigBuffer> create(HailoRTDriver &driver, uint8_t channel_index,
+ const std::vector<uint32_t> &cfg_sizes);
+
+ // Write data to config channel
+ hailo_status write(const void *data, size_t data_size);
+
+ // Program the descriptors for the data written so far
+ Expected<uint32_t> program_descriptors();
+
+ size_t get_current_buffer_size();
+
+ /* Get all the config size. It's not the same as the VdmaBuffer::size()
+ since we might add NOPs to the data (Pre-fetch mode) */
+ size_t get_total_cfg_size();
+
+ vdma::VdmaBuffer::Type buffer_type() const;
+ uint16_t desc_page_size() const;
+ uint64_t dma_address() const;
+ uint32_t total_desc_count() const;
+
+ uint32_t acc_desc_count() const;
+
+private:
+ ConfigBuffer(std::unique_ptr<vdma::VdmaBuffer> &&buffer, size_t total_buffer_size);
+
+ static Expected<std::unique_ptr<vdma::VdmaBuffer>> create_sg_buffer(HailoRTDriver &driver,
+ uint8_t channel_index, const std::vector<uint32_t> &cfg_sizes);
+ static Expected<std::unique_ptr<vdma::VdmaBuffer>> create_ccb_buffer(HailoRTDriver &driver,
+ uint32_t buffer_size);
+
+ static bool should_use_ccb(HailoRTDriver &driver);
+
+ std::unique_ptr<vdma::VdmaBuffer> m_buffer;
+ const size_t m_total_buffer_size;
+ size_t m_acc_buffer_offset;
+ uint32_t m_acc_desc_count;
+ size_t m_current_buffer_size;
+};
+
+} /* hailort */
+
+#endif /* _HAILO_CONFIG_BUFFER_HPP_ */
\ No newline at end of file
virtual ~ConfigManager() {}
virtual ConfigManagerType get_manager_type() = 0;
virtual Expected<ConfiguredNetworkGroupVector> add_hef(Hef &hef, const std::map<std::string,
- ConfigureNetworkParams> &configure_params={}) = 0;
+ ConfigureNetworkParams> &configure_params, bool is_scheduler_used = false) = 0;
protected:
hailo_status validate_boundary_streams_were_created(Hef &hef, const std::string &network_group_name, ConfiguredNetworkGroup &network_group)
{
Expected<HcpConfigActivatedNetworkGroup> HcpConfigActivatedNetworkGroup::create(Device &device, std::vector<WriteMemoryInfo> &config,
+ const std::string &network_group_name,
const hailo_activate_network_group_params_t &network_group_params,
std::map<std::string, std::unique_ptr<InputStream>> &input_streams,
std::map<std::string, std::unique_ptr<OutputStream>> &output_streams,
CHECK_SUCCESS_AS_EXPECTED(status);
}
- HcpConfigActivatedNetworkGroup object(device, active_net_group_holder, network_group_params, input_streams, output_streams,
+ HcpConfigActivatedNetworkGroup object(device, active_net_group_holder, network_group_name, network_group_params, input_streams, output_streams,
power_mode, std::move(network_group_activated_event), status);
CHECK_SUCCESS_AS_EXPECTED(status);
return object;
}
-HcpConfigActivatedNetworkGroup::HcpConfigActivatedNetworkGroup(Device &device,
- HcpConfigActiveAppHolder &active_net_group_holder, const hailo_activate_network_group_params_t &network_group_params,
- std::map<std::string, std::unique_ptr<InputStream>> &input_streams,
- std::map<std::string, std::unique_ptr<OutputStream>> &output_streams,
- hailo_power_mode_t power_mode, EventPtr &&network_group_activated_event, hailo_status &status) :
- ActivatedNetworkGroupBase(network_group_params, input_streams, output_streams,
- std::move(network_group_activated_event), status),
- m_active_net_group_holder(active_net_group_holder), m_is_active(true), m_power_mode(power_mode), m_device(device)
+HcpConfigActivatedNetworkGroup::HcpConfigActivatedNetworkGroup(
+ Device &device,
+ HcpConfigActiveAppHolder &active_net_group_holder,
+ const std::string &network_group_name,
+ const hailo_activate_network_group_params_t &network_group_params,
+ std::map<std::string, std::unique_ptr<InputStream>> &input_streams,
+ std::map<std::string, std::unique_ptr<OutputStream>> &output_streams,
+ hailo_power_mode_t power_mode,
+ EventPtr &&network_group_activated_event,
+ hailo_status &status) :
+ ActivatedNetworkGroupBase(network_group_params, CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE,
+ input_streams, output_streams, std::move(network_group_activated_event), status),
+ m_active_net_group_holder(active_net_group_holder),
+ m_is_active(true),
+ m_power_mode(power_mode),
+ m_device(device),
+ m_network_group_name(network_group_name)
{
// Validate ActivatedNetworkGroup status
if (HAILO_SUCCESS != status) {
}
}
+const std::string &HcpConfigActivatedNetworkGroup::get_network_group_name() const
+{
+ return m_network_group_name;
+}
+
} /* namespace hailort */
{
Expected<ConfiguredNetworkGroupVector> HcpConfigManager::add_hef(Hef &hef,
- const NetworkGroupsParamsMap &configure_params)
+ const NetworkGroupsParamsMap &configure_params, bool /*is_scheduler_used*/)
{
auto &hef_network_groups = hef.pimpl->network_groups();
auto current_net_group_index = static_cast<uint8_t>(m_net_groups.size());
auto net_group_ptr = make_shared_nothrow<HcpConfigNetworkGroup>(std::move(single_context_app));
CHECK_AS_EXPECTED(nullptr != net_group_ptr, HAILO_OUT_OF_HOST_MEMORY);
m_net_groups.emplace_back(net_group_ptr);
- added_network_groups.emplace_back(std::static_pointer_cast<ConfiguredNetworkGroup>(net_group_ptr));
+
+ auto net_group_wrapper = ConfiguredNetworkGroupWrapper::create(net_group_ptr);
+ CHECK_EXPECTED(net_group_wrapper);
+
+ auto net_group_wrapper_ptr = make_shared_nothrow<ConfiguredNetworkGroupWrapper>(net_group_wrapper.release());
+ CHECK_AS_EXPECTED(nullptr != net_group_wrapper_ptr, HAILO_OUT_OF_HOST_MEMORY);
+ m_net_group_wrappers.emplace_back(net_group_wrapper_ptr);
+
+ added_network_groups.emplace_back(std::static_pointer_cast<ConfiguredNetworkGroup>(net_group_wrapper_ptr));
current_net_group_index++;
m_config(std::move(config)), m_active_net_group_holder(active_net_group_holder), m_device(device)
{}
-Expected<std::unique_ptr<ActivatedNetworkGroup>> HcpConfigNetworkGroup::activate(
- const hailo_activate_network_group_params_t &network_group_params)
+Expected<std::unique_ptr<ActivatedNetworkGroup>> HcpConfigNetworkGroup::activate_impl(
+ const hailo_activate_network_group_params_t &network_group_params, uint16_t /* dynamic_batch_size */)
{
auto start_time = std::chrono::steady_clock::now();
- auto activated_net_group = HcpConfigActivatedNetworkGroup::create(m_device, m_config, network_group_params,
+ auto activated_net_group = HcpConfigActivatedNetworkGroup::create(m_device, m_config, get_network_group_name(), network_group_params,
m_input_streams, m_output_streams, m_active_net_group_holder, m_config_params.power_mode,
m_network_group_activated_event);
CHECK_EXPECTED(activated_net_group);
static_cast<uint8_t>(stream_index + OUTPUT_CHANNEL_INDEX_OFFSET);
}
+hailo_status HcpConfigNetworkGroup::set_scheduler_timeout(const std::chrono::milliseconds &timeout, const std::string &network_name)
+{
+ (void) timeout;
+ (void) network_name;
+ return HAILO_INVALID_OPERATION;
+}
+
+hailo_status HcpConfigNetworkGroup::set_scheduler_threshold(uint32_t threshold, const std::string &network_name)
+{
+ (void) threshold;
+ (void) network_name;
+ return HAILO_INVALID_OPERATION;
+}
+
+Expected<std::shared_ptr<LatencyMetersMap>> HcpConfigNetworkGroup::get_latnecy_meters()
+{
+ /* hcp does not support latnecy. return empty map */
+ LatencyMetersMap empty_map;
+ return make_shared_nothrow<LatencyMetersMap>(empty_map);
+}
+
+Expected<std::shared_ptr<VdmaChannel>> HcpConfigNetworkGroup::get_boundary_vdma_channel_by_stream_name(
+ const std::string &stream_name)
+{
+ LOGGER__ERROR("get_boundary_vdma_channel_by_stream_name function for stream name {} is not supported in hcp config manager",
+ stream_name);
+ return make_unexpected(HAILO_INVALID_OPERATION);
+}
+
} /* namespace hailort */
uint8_t **action_data_current_offset,
uint8_t cluster_index,
uint8_t lcu_index,
+ uint8_t network_index,
bool is_repeated)
{
hailo_status status = HAILO_UNINITIALIZED;
enable_lcu_action.header.is_repeated = is_repeated;
enable_lcu_action.cluster_index = cluster_index;
enable_lcu_action.lcu_index = lcu_index;
+ enable_lcu_action.network_index = network_index;
status = hef_metadata__update_slicing_info(context_info, action_data_current_offset,
sizeof(enable_lcu_action), true);
}
hailo_status HEF_METADATA__add_inter_context_output_edge_layer(
- CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
- uint8_t **edge_layer_current_offset,
- uint8_t stream_index,
- uint8_t vdma_channel_index,
- uint8_t network_index,
- const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
- uint32_t frame_credits_in_bytes,
- uint64_t host_descriptors_base_address,
- uint16_t initial_host_available_descriptors,
- uint16_t desc_page_size,
- uint8_t desc_list_depth)
+ CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
+ uint8_t **edge_layer_current_offset,
+ uint8_t stream_index,
+ uint8_t vdma_channel_index,
+ uint8_t network_index,
+ const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
+ const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info)
{
hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__inter_context_output_t *edge_layer_info = nullptr;
network_index,
nn_stream_config);
- edge_layer_info->frame_credits_in_bytes = frame_credits_in_bytes;
- edge_layer_info->host_desc_address_info.host_descriptors_base_address = host_descriptors_base_address;
- edge_layer_info->host_desc_address_info.initial_host_available_descriptors = initial_host_available_descriptors;
- edge_layer_info->desc_page_size = desc_page_size;
- edge_layer_info->host_desc_address_info.desc_list_depth = desc_list_depth;
+ edge_layer_info->host_buffer_info = host_buffer_info;
*(edge_layer_current_offset) += sizeof(*edge_layer_info);
const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
uint32_t frame_credits_in_bytes,
uint64_t host_descriptors_base_address,
- uint16_t initial_host_available_descriptors,
uint16_t desc_page_size,
uint8_t desc_list_depth,
- bool fw_managed_channel)
+ uint32_t buffered_rows_count)
{
hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__ddr_buffer_output_t *edge_layer_info = nullptr;
edge_layer_info->frame_credits_in_bytes = frame_credits_in_bytes;
edge_layer_info->host_desc_address_info.host_descriptors_base_address = host_descriptors_base_address;
- edge_layer_info->host_desc_address_info.initial_host_available_descriptors = initial_host_available_descriptors;
edge_layer_info->desc_page_size = desc_page_size;
edge_layer_info->host_desc_address_info.desc_list_depth = desc_list_depth;
- edge_layer_info->fw_managed_channel = fw_managed_channel;
+ edge_layer_info->buffered_rows_count = buffered_rows_count;
return HAILO_SUCCESS;
}
hailo_status HEF_METADATA__add_network_boundary_input_edge_layer(
- CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
- uint8_t **edge_layer_current_offset,
- uint8_t stream_index,
- uint8_t vdma_channel_index,
- uint8_t network_index,
- const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
- uint16_t desc_page_size)
+ CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
+ uint8_t **edge_layer_current_offset,
+ uint8_t stream_index,
+ uint8_t vdma_channel_index,
+ uint8_t network_index,
+ const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
+ uint16_t desc_page_size,
+ uint32_t initial_credit_size)
{
hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__network_boundary_input_t *edge_layer_info = nullptr;
nn_stream_config);
edge_layer_info->desc_page_size = desc_page_size;
+ edge_layer_info->initial_credit_size = initial_credit_size;
*(edge_layer_current_offset) += sizeof(*edge_layer_info);
}
hailo_status HEF_METADATA__add_inter_context_input_edge_layer(
- CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
- uint8_t **edge_layer_current_offset,
- uint8_t stream_index,
- uint8_t vdma_channel_index,
- uint8_t network_index,
- const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
- uint16_t context_credits_in_descriptors,
- uint64_t host_descriptors_base_address,
- uint8_t desc_list_depth,
- uint16_t desc_page_size)
+ CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
+ uint8_t **edge_layer_current_offset,
+ uint8_t stream_index,
+ uint8_t vdma_channel_index,
+ uint8_t network_index,
+ const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
+ const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info,
+ uint32_t initial_credit_size)
{
hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__inter_context_input_t *edge_layer_info = nullptr;
network_index,
nn_stream_config);
- edge_layer_info->context_credits_in_descriptors = context_credits_in_descriptors;
- edge_layer_info->host_desc_address_info.host_descriptors_base_address = host_descriptors_base_address;
- edge_layer_info->host_desc_address_info.initial_host_available_descriptors = 0;
- edge_layer_info->host_desc_address_info.desc_list_depth = desc_list_depth;
- edge_layer_info->desc_page_size = desc_page_size;
+ edge_layer_info->host_buffer_info = host_buffer_info;
+ edge_layer_info->initial_credit_size = initial_credit_size;
*(edge_layer_current_offset) += sizeof(*edge_layer_info);
}
hailo_status HEF_METADATA__add_ddr_buffer_input_edge_layer(
- CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
- uint8_t **edge_layer_current_offset,
- uint8_t stream_index,
- uint8_t vdma_channel_index,
- uint8_t network_index,
- const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
- uint64_t host_descriptors_base_address,
- uint8_t desc_list_depth,
- bool fw_managed_channel)
+ CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
+ uint8_t **edge_layer_current_offset,
+ uint8_t stream_index,
+ uint8_t vdma_channel_index,
+ uint8_t network_index,
+ const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
+ uint64_t host_descriptors_base_address,
+ uint8_t desc_list_depth,
+ uint32_t initial_credit_size)
{
hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__ddr_buffer_input_t *edge_layer_info = nullptr;
nn_stream_config);
edge_layer_info->host_desc_address_info.host_descriptors_base_address = host_descriptors_base_address;
- edge_layer_info->host_desc_address_info.initial_host_available_descriptors = 0;
edge_layer_info->host_desc_address_info.desc_list_depth = desc_list_depth;
- edge_layer_info->fw_managed_channel = fw_managed_channel;
+ edge_layer_info->initial_credit_size = initial_credit_size;
*(edge_layer_current_offset) += sizeof(*edge_layer_info);
return HAILO_SUCCESS;
}
+
+hailo_status HEF_METADATA__burst_credits_task_start(
+ CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
+ uint8_t **action_data_current_offset,
+ bool is_repeated)
+{
+ hailo_status status = HAILO_UNINITIALIZED;
+ CONTROL_PROTOCOL__BURST_CREDITS_TASK_START_ACTION_T burst_credits_task_start{};
+
+ CHECK_ARG_NOT_NULL(action_data_current_offset);
+ CHECK_ARG_NOT_NULL(*action_data_current_offset);
+
+ burst_credits_task_start.header.action_type = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_BURST_CREDITS_TASK_START;
+ burst_credits_task_start.header.is_repeated = is_repeated;
+
+ status = hef_metadata__update_slicing_info(context_info,
+ action_data_current_offset,
+ sizeof(burst_credits_task_start),
+ true);
+ CHECK_SUCCESS(status);
+
+ memcpy((*action_data_current_offset), &burst_credits_task_start, sizeof(burst_credits_task_start));
+ *(action_data_current_offset) += sizeof(burst_credits_task_start);
+
+ return HAILO_SUCCESS;
+}
/* End of context switch info build functions */
} /* namespace hailort */
* @param[out] action - pointer to the action
* @param[in] cluster_index - cluster index
* @param[in] lcu_index - lcu_index
+ * @param[in] network_index - network index
* @param[in] is_repeated - 'true' if the action is part of a "repeated sequence" (a group of consecutive actions
* with the same type)
*
uint8_t **action_data_current_offset,
uint8_t cluster_index,
uint8_t lcu_index,
+ uint8_t network_index,
bool is_repeated);
/**
* @param[in] vdma_channel_index - channel index
* @param[in] network_index - network index
* @param[in] nn_stream_config
- * @param[in] frame_credits_in_bytes - context credits in bytes
- * @param[in] host_descriptors_base_address - host descritpors base address
- * @param[in] initial_host_available_descriptors - initial host available descriptors, initialized by the FW once new context
- * start
- * @param[in] desc_page_size - descriptor page_size in bytes
- * @param[in] desc_list_depth - descriptor list depth
- *
+ * @param[in] host_buffer_info - info about host buffer
*/
hailo_status HEF_METADATA__add_inter_context_output_edge_layer(
CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
uint8_t vdma_channel_index,
uint8_t network_index,
const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
- uint32_t frame_credits_in_bytes,
- uint64_t host_descriptors_base_address,
- uint16_t initial_host_available_descriptors,
- uint16_t desc_page_size,
- uint8_t desc_list_depth);
+ const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info);
/**
* build edge layer - vdma DDR buffer output
* @param[in] nn_stream_config
* @param[in] frame_credits_in_bytes - context credits in bytes
* @param[in] host_descriptors_base_address - host descritpors base address
- * @param[in] initial_host_available_descriptors - initial host available descriptors, initialized by the FW once new context
- * start
* @param[in] desc_page_size - descriptor page_size in bytes
* @param[in] desc_list_depth - descriptor list depth
- * @param[in] fw_managed_channel - descriptor list depth
+ * @param[in] buffered_rows_count - amount of rows to buffer.
*
*/
hailo_status HEF_METADATA__add_ddr_buffer_output_edge_layer(
const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
uint32_t frame_credits_in_bytes,
uint64_t host_descriptors_base_address,
- uint16_t initial_host_available_descriptors,
uint16_t desc_page_size,
uint8_t desc_list_depth,
- bool fw_managed_channel);
+ uint32_t buffered_rows_count);
/**
* build edge layer - vdma network boundary input
* @param[in] network_index - network index
* @param[in] nn_stream_config
* @param[in] desc_page_size - desc page size in bytes
+ * @param[in] initial_credit_size - initial credit size, if 0 is set the firmware takes its default value.
*
*/
hailo_status HEF_METADATA__add_network_boundary_input_edge_layer(
uint8_t vdma_channel_index,
uint8_t network_index,
const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
- uint16_t desc_page_size);
+ uint16_t desc_page_size,
+ uint32_t initial_credit_size);
/**
* build edge layer - vdma intermediate buffer input
* @param[in] vdma_channel_index - channel index
* @param[in] network_index - network index
* @param[in] nn_stream_config
- * @param[in] context_credits_in_descriptors - context credits in descriptors
- * @param[in] host_descriptors_base_address - host descritpors base address
- * @param[in] desc_page_size - desc page size in bytes
+ * @param[in] host_buffer_info - info about host buffer
+ * @param[in] initial_credit_size - initial credit size, if 0 is set the firmware takes its default value.
*
*/
hailo_status HEF_METADATA__add_inter_context_input_edge_layer(
uint8_t vdma_channel_index,
uint8_t network_index,
const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
- uint16_t context_credits_in_descriptors,
- uint64_t host_descriptors_base_address,
- uint8_t desc_list_depth,
- uint16_t desc_page_size);
+ const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info,
+ uint32_t initial_credit_size);
/**
* build edge layer - vdma ddr buffer input
* @param[in] vdma_channel_index - channel index
* @param[in] network_index - network index
* @param[in] nn_stream_config
- * @param[in] context_credits_in_descriptors - context credits in descriptors
* @param[in] host_descriptors_base_address - host descritpors base address
* @param[in] desc_list_depth - descriptor list depth
- * @param[in] fw_managed_channel - descriptor list depth
- *
+ * @param[in] initial_credit_size - initial credit size, if 0 is set the firmware takes its default value.
*/
hailo_status HEF_METADATA__add_ddr_buffer_input_edge_layer(
CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
uint64_t host_descriptors_base_address,
uint8_t desc_list_depth,
- bool fw_managed_channel);
+ uint32_t initial_credit_size);
/**
* Build add ddr pair info action
const uint32_t descriptors_per_frame,
const uint16_t programmed_descriptors_count,
bool is_repeated);
+
/**
* Build add ddr buffering start
*
uint8_t **action_data_current_offset,
bool is_repeated);
+/**
+ * Build add burst credits task start
+ *
+ * @param[in] context_info - struct holding all the context info
+ * @param[out] action_data_current_offset - pointer to the action
+ * @param[in] is_repeated - 'true' if the action is part of a "repeated sequence" (a group of consecutive actions
+ * with the same type)
+ *
+ */
+hailo_status HEF_METADATA__burst_credits_task_start(
+ CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
+ uint8_t **action_data_current_offset,
+ bool is_repeated);
+
} /* namespace hailort */
#endif /* __CONTEXT_SWITCH__ */
#include "hailo/hailort.h"
#include "intermediate_buffer.hpp"
-#include "vdma_buffer.hpp"
+#include "config_buffer.hpp"
#include "vdma_channel.hpp"
-#include "vdma_descriptor_list.hpp"
#include "control_protocol.hpp"
#include "pcie_device.hpp"
std::string m_layer_name;
};
-
-class ConfigResources final
-{
-public:
- ConfigResources(HailoRTDriver &driver, VdmaBuffer &&buffer, VdmaDescriptorList &&descriptor,
- uint16_t requested_desc_page_size, size_t total_buffer_size);
-
- // Write data to config channel
- hailo_status write(const void *data, size_t data_size);
-
- // Program the descriptors for the data written so far
- Expected<uint16_t> program_descriptors();
-
- uint16_t get_page_size();
-
- size_t get_current_buffer_size();
-
- /* Get all the config size. It's not the same as the VdmaBuffer::size()
- since we might add NOPs to the data (Pre-fetch mode) */
- size_t get_total_cfg_size();
-
-private:
- VdmaBuffer m_buffer;
- VdmaDescriptorList m_descriptor;
- const uint16_t m_desc_page_size;
- const size_t m_total_buffer_size;
- size_t m_acc_buffer_offset;
- uint16_t m_acc_desc_count;
- size_t m_current_buffer_size;
-
- friend class ResourcesManager;
-};
-
-
class ResourcesManager final
{
public:
m_inter_context_channels(std::move(other.m_inter_context_channels)),
m_config_channels(std::move(other.m_config_channels)), m_ddr_buffer_channels(std::move(other.m_ddr_buffer_channels)),
m_network_group_metadata(std::move(other.m_network_group_metadata)), m_net_group_index(other.m_net_group_index),
- m_network_index_map(std::move(other.m_network_index_map)) {}
+ m_network_index_map(std::move(other.m_network_index_map)),
+ m_latency_meters(std::move(other.m_latency_meters)),
+ m_boundary_channels(std::move(other.m_boundary_channels)) {}
ExpectedRef<IntermediateBuffer> create_inter_context_buffer(uint32_t transfer_size, uint8_t src_stream_index,
- uint8_t src_context_index, const std::string &partial_network_name);
+ uint8_t src_context_index, const std::string &network_name);
ExpectedRef<IntermediateBuffer> get_intermediate_buffer(const IntermediateBufferKey &key);
- Expected<std::pair<uint16_t, uint32_t>> get_desc_buffer_sizes_for_boundary_channel(uint32_t transfer_size,
- const std::string &partial_network_name);
+ Expected<std::shared_ptr<VdmaChannel>> create_boundary_vdma_channel(uint8_t channel_index, uint32_t transfer_size,
+ const std::string &network_name, const std::string &stream_name,
+ VdmaChannel::Direction channel_direction);
+
ExpectedRef<IntermediateBuffer> create_ddr_buffer(DdrChannelsInfo &ddr_info, uint8_t context_index);
- Expected<CONTROL_PROTOCOL__application_header_t> get_control_network_group_header();
+ Expected<CONTROL_PROTOCOL__application_header_t> get_control_network_group_header(bool is_scheduler_used);
using context_info_t = CONTROL_PROTOCOL__context_switch_context_info_t;
return m_contexts;
}
- std::vector<ConfigResources> &preliminary_config()
+ std::vector<ConfigBuffer> &preliminary_config()
{
return m_preliminary_config;
}
- std::vector<ConfigResources> &dynamic_config(uint8_t context_index)
+ std::vector<ConfigBuffer> &dynamic_config(uint8_t context_index)
{
assert(context_index < m_dynamic_config.size());
return m_dynamic_config[context_index];
return m_vdma_device.get_dev_id();
}
+ LatencyMetersMap &get_latnecy_meters()
+ {
+ return m_latency_meters;
+ }
+
Expected<uint8_t> get_boundary_channel_index(uint8_t stream_index,
hailo_stream_direction_t direction, const std::string &layer_name);
Expected<hailo_stream_interface_t> get_default_streams_interface();
Expected<Buffer> read_intermediate_buffer(const IntermediateBufferKey &key);
hailo_status set_number_of_cfg_channels(const uint8_t number_of_cfg_channels);
- static Expected<ConfigResources> create_config_resources(uint8_t channel_index,
- const std::vector<uint32_t> &cfg_sizes, HailoRTDriver &driver);
void update_preliminary_config_buffer_info();
void update_dynamic_contexts_buffer_info();
- hailo_status create_vdma_channels();
+ hailo_status create_internal_vdma_channels();
hailo_status register_fw_managed_vdma_channels();
hailo_status unregister_fw_managed_vdma_channels();
+ hailo_status set_inter_context_channels_dynamic_batch_size(uint16_t dynamic_batch_size);
hailo_status open_ddr_channels();
void abort_ddr_channels();
void close_ddr_channels();
- hailo_status enable_state_machine();
+ hailo_status enable_state_machine(uint16_t dynamic_batch_size);
hailo_status reset_state_machine();
- Expected<uint16_t> get_network_batch_size_from_partial_name(const std::string &partial_network_name) const;
- hailo_status fill_network_batch_size(CONTROL_PROTOCOL__application_header_t &app_header);
+ Expected<uint16_t> get_network_batch_size(const std::string &network_name) const;
+ Expected<std::shared_ptr<VdmaChannel>> get_boundary_vdma_channel_by_stream_name(const std::string &stream_name);
+
private:
- ExpectedRef<IntermediateBuffer> create_intermediate_buffer(uint32_t transfer_size, uint16_t batch_size,
- const IntermediateBufferKey &key);
+ ExpectedRef<IntermediateBuffer> create_intermediate_buffer(IntermediateBuffer::ChannelType channel_type,
+ uint32_t transfer_size, uint16_t batch_size, const IntermediateBufferKey &key);
+ void update_config_buffer_info(std::vector<ConfigBuffer> &config_buffers,
+ CONTROL_PROTOCOL__context_switch_context_info_t &context);
+ hailo_status fill_infer_features(CONTROL_PROTOCOL__application_header_t &app_header);
+ hailo_status fill_network_batch_size(CONTROL_PROTOCOL__application_header_t &app_header, bool is_scheduler_used);
std::vector<DdrChannelsInfo> m_ddr_infos;
std::vector<CONTROL_PROTOCOL__context_switch_context_info_t> m_contexts;
VdmaDevice &m_vdma_device;
HailoRTDriver &m_driver;
const ConfigureNetworkParams m_config_params;
- std::vector<ConfigResources> m_preliminary_config;
+ std::vector<ConfigBuffer> m_preliminary_config;
// m_dynamic_config[context_index][config_index]
- std::vector<std::vector<ConfigResources>> m_dynamic_config;
- std::map<IntermediateBufferKey, std::unique_ptr<IntermediateBuffer>> m_intermediate_buffers;
+ std::vector<std::vector<ConfigBuffer>> m_dynamic_config;
+ std::map<IntermediateBufferKey, IntermediateBuffer> m_intermediate_buffers;
std::vector<VdmaChannel> m_inter_context_channels;
std::vector<VdmaChannel> m_config_channels;
std::vector<VdmaChannel> m_ddr_buffer_channels;
std::shared_ptr<NetworkGroupMetadata> m_network_group_metadata;
uint8_t m_net_group_index;
const std::vector<std::string> m_network_index_map;
+ LatencyMetersMap m_latency_meters; // Latency meter per network
+ std::map<std::string, std::shared_ptr<VdmaChannel>> m_boundary_channels; //map of string name and connected vDMA channel
ResourcesManager(VdmaDevice &vdma_device, HailoRTDriver &driver,
- const ConfigureNetworkParams config_params, std::vector<ConfigResources> &&preliminary_config,
- std::vector<std::vector<ConfigResources>> &&dynamic_config, std::shared_ptr<NetworkGroupMetadata> &&network_group_metadata, uint8_t net_group_index,
- const std::vector<std::string> &&network_index_map) :
+ const ConfigureNetworkParams config_params, std::vector<ConfigBuffer> &&preliminary_config,
+ std::vector<std::vector<ConfigBuffer>> &&dynamic_config, std::shared_ptr<NetworkGroupMetadata> &&network_group_metadata, uint8_t net_group_index,
+ const std::vector<std::string> &&network_index_map, LatencyMetersMap &&latency_meters) :
m_vdma_device(vdma_device), m_driver(driver), m_config_params(config_params),
m_preliminary_config(std::move(preliminary_config)), m_dynamic_config(std::move(dynamic_config)),
- m_network_group_metadata(std::move(network_group_metadata)), m_net_group_index(net_group_index), m_network_index_map(std::move(network_index_map)) {};
+ m_network_group_metadata(std::move(network_group_metadata)), m_net_group_index(net_group_index), m_network_index_map(std::move(network_index_map)),
+ m_latency_meters(std::move(latency_meters)) {};
};
static Expected<VdmaConfigActivatedNetworkGroup> create(
VdmaConfigActiveAppHolder &active_net_group_holder,
+ const std::string &network_group_name,
std::vector<std::shared_ptr<ResourcesManager>> resources_managers,
const hailo_activate_network_group_params_t &network_group_params,
+ uint16_t dynamic_batch_size,
std::map<std::string, std::unique_ptr<InputStream>> &input_streams,
- std::map<std::string, std::unique_ptr<OutputStream>> &output_streams,
+ std::map<std::string, std::unique_ptr<OutputStream>> &output_streams,
EventPtr network_group_activated_event,
AccumulatorPtr deactivation_time_accumulator);
VdmaConfigActivatedNetworkGroup &operator=(VdmaConfigActivatedNetworkGroup &&other) = delete;
VdmaConfigActivatedNetworkGroup(VdmaConfigActivatedNetworkGroup &&other) noexcept;
+ virtual const std::string &get_network_group_name() const override;
virtual Expected<Buffer> get_intermediate_buffer(const IntermediateBufferKey &key) override;
private:
VdmaConfigActivatedNetworkGroup(
+ const std::string &network_group_name,
const hailo_activate_network_group_params_t &network_group_params,
+ uint16_t dynamic_batch_size,
std::map<std::string, std::unique_ptr<InputStream>> &input_streams,
std::map<std::string, std::unique_ptr<OutputStream>> &output_streams,
std::vector<std::shared_ptr<ResourcesManager>> &&resources_managers,
static void ddr_send_thread_main(DdrChannelsInfo ddr_info,
std::shared_ptr<std::atomic<uint16_t>> desc_list_num_ready);
+ std::string m_network_group_name;
bool m_should_reset_state_machine;
VdmaConfigActiveAppHolder &m_active_net_group_holder;
// One ResourcesManager per connected physical device. Currently only one device is supported.
#define HAILO_VDMA_CONFIG_MANAGER_HPP_
#include "context_switch/config_manager.hpp"
+#include "context_switch/network_group_wrapper.hpp"
#include "context_switch/multi_context/vdma_config_network_group.hpp"
#include "hailo/hailort.h"
#include "hailo/device.hpp"
#include "common/utils.hpp"
#include "hlpcie.hpp"
#include "vdma_channel.hpp"
-#include "vdma_buffer.hpp"
-#include "vdma_descriptor_list.hpp"
+#include "network_group_scheduler.hpp"
#include <vector>
#include <map>
static Expected<VdmaConfigManager> create(VDevice &vdevice);
virtual ConfigManagerType get_manager_type();
virtual Expected<ConfiguredNetworkGroupVector> add_hef(Hef &hef,
- const NetworkGroupsParamsMap &configure_params={});
+ const NetworkGroupsParamsMap &configure_params, bool is_scheduler_used=false);
static hailo_status update_network_batch_size(ConfigureNetworkParams &configure_params);
- virtual ~VdmaConfigManager() {}
+ virtual ~VdmaConfigManager() = default;
VdmaConfigManager(const VdmaConfigManager &other) noexcept = delete;
VdmaConfigManager &operator=(const VdmaConfigManager &other) = delete;
VdmaConfigManager &operator=(VdmaConfigManager &&other) = delete;
VdmaConfigManager(VdmaConfigManager &&other) noexcept = default;
private:
- VdmaConfigManager(std::vector<std::reference_wrapper<VdmaDevice>> &&devices, bool is_vdevice);
+ VdmaConfigManager(std::vector<std::reference_wrapper<VdmaDevice>> &&devices, bool is_vdevice, NetworkGroupSchedulerWeakPtr network_group_scheduler);
// TODO: (SDK-16665) Dont need is_active flag for dtor?
std::vector<std::reference_wrapper<VdmaDevice>> m_devices;
std::vector<std::shared_ptr<VdmaConfigNetworkGroup>> m_net_groups;
+ std::vector<std::shared_ptr<ConfiguredNetworkGroupWrapper>> m_net_group_wrappers;
VdmaConfigActiveAppHolder m_active_net_group_holder;
bool m_is_vdevice;
+ NetworkGroupSchedulerWeakPtr m_network_group_scheduler;
};
} /* namespace hailort */
#define _HAILO_CONTEXT_SWITCH_VDMA_CONFIG_NETWORK_GROUP_HPP_
#include "hailo/hailort.h"
-#include "vdma_buffer.hpp"
#include "vdma_channel.hpp"
-#include "vdma_descriptor_list.hpp"
#include "common/utils.hpp"
#include "context_switch/multi_context/vdma_config_activated_network_group.hpp"
#include "control_protocol.h"
#include "hailort_defaults.hpp"
#include "context_switch/network_group_internal.hpp"
#include "context_switch/multi_context/resource_manager.hpp"
+#include "network_group_scheduler.hpp"
#include <cstdint>
#include <assert.h>
static Expected<VdmaConfigNetworkGroup> create(VdmaConfigActiveAppHolder &active_net_group_holder,
const ConfigureNetworkParams &config_params,
std::vector<std::shared_ptr<ResourcesManager>> resources_managers,
- std::shared_ptr<NetworkGroupMetadata> network_group_metadata);
+ std::shared_ptr<NetworkGroupMetadata> network_group_metadata, NetworkGroupSchedulerWeakPtr network_group_scheduler);
std::vector<std::shared_ptr<ResourcesManager>> &get_resources_managers()
{
return m_resources_managers;
}
- hailo_status create_vdevice_streams_from_config_params();
+ hailo_status create_vdevice_streams_from_config_params(network_group_handle_t network_group_handle);
hailo_status create_output_vdevice_stream_from_config_params(
- const hailo_stream_parameters_t &stream_params, const std::string &stream_name);
+ const hailo_stream_parameters_t &stream_params, const std::string &stream_name, network_group_handle_t network_group_handle);
hailo_status create_input_vdevice_stream_from_config_params(
- const hailo_stream_parameters_t &stream_params, const std::string &stream_name);
+ const hailo_stream_parameters_t &stream_params, const std::string &stream_name, network_group_handle_t network_group_handle);
- virtual Expected<std::unique_ptr<ActivatedNetworkGroup>> activate(
- const hailo_activate_network_group_params_t &network_group_params = HailoRTDefaults::get_network_group_params()) override;
+ virtual Expected<std::unique_ptr<ActivatedNetworkGroup>> activate_impl(
+ const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) override;
virtual Expected<hailo_stream_interface_t> get_default_streams_interface() override;
virtual Expected<uint8_t> get_boundary_channel_index(uint8_t stream_index, hailo_stream_direction_t direction,
const std::string &layer_name) override;
+ virtual Expected<std::shared_ptr<LatencyMetersMap>> get_latnecy_meters() override;
+ virtual Expected<std::shared_ptr<VdmaChannel>> get_boundary_vdma_channel_by_stream_name(
+ const std::string &stream_name) override;
+
+ void set_network_group_handle(network_group_handle_t handle);
+ virtual hailo_status set_scheduler_timeout(const std::chrono::milliseconds &timeout, const std::string &network_name) override;
+ virtual hailo_status set_scheduler_threshold(uint32_t threshold, const std::string &network_name) override;
virtual ~VdmaConfigNetworkGroup() = default;
VdmaConfigNetworkGroup(const VdmaConfigNetworkGroup &other) = delete;
VdmaConfigNetworkGroup &operator=(VdmaConfigNetworkGroup &&other) = delete;
VdmaConfigNetworkGroup(VdmaConfigNetworkGroup &&other) noexcept : ConfiguredNetworkGroupBase(std::move(other)),
m_active_net_group_holder(other.m_active_net_group_holder),
- m_resources_managers(std::move(other.m_resources_managers)) {}
+ m_resources_managers(std::move(other.m_resources_managers)), m_network_group_scheduler(std::move(other.m_network_group_scheduler)) {}
private:
VdmaConfigNetworkGroup(VdmaConfigActiveAppHolder &active_net_group_holder,
const ConfigureNetworkParams &config_params,
std::vector<std::shared_ptr<ResourcesManager>> &&resources_managers,
- const NetworkGroupMetadata &network_group_metadata, hailo_status &status);
+ const NetworkGroupMetadata &network_group_metadata, NetworkGroupSchedulerWeakPtr network_group_scheduler, hailo_status &status);
VdmaConfigActiveAppHolder &m_active_net_group_holder;
std::vector<std::shared_ptr<ResourcesManager>> m_resources_managers;
+ NetworkGroupSchedulerWeakPtr m_network_group_scheduler;
+ network_group_handle_t m_network_group_handle;
+
};
} /* namespace hailort */
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file network_group.cpp
+ * @brief: Configured Network Group and Activated Network Group
+ **/
+
#include "hailo/transform.hpp"
#include "network_group_internal.hpp"
#include "hef_internal.hpp"
{
ActivatedNetworkGroupBase::ActivatedNetworkGroupBase(const hailo_activate_network_group_params_t &network_group_params,
- std::map<std::string, std::unique_ptr<InputStream>> &input_streams, std::map<std::string, std::unique_ptr<OutputStream>> &output_streams,
+ uint16_t dynamic_batch_size,
+ std::map<std::string, std::unique_ptr<InputStream>> &input_streams,
+ std::map<std::string, std::unique_ptr<OutputStream>> &output_streams,
EventPtr &&network_group_activated_event, hailo_status &status) :
m_network_group_params(network_group_params),
m_input_streams(input_streams),
return;
}
- status = activate_low_level_streams();
+ status = activate_low_level_streams(dynamic_batch_size);
if (HAILO_SUCCESS != status) {
LOGGER__ERROR("Failed to activate low level streams");
return;
}
}
-Expected<LatencyMeterPtr> ConfiguredNetworkGroupBase::create_hw_latency_meter(Device &device,
- const std::vector<LayerInfo> &layers)
-{
- std::set<uint32_t> d2h_channel_indexes;
-
- // TODO: dont support hw latency meter with MIPI input
-
- if (Device::Type::PCIE != device.get_type()) {
- LOGGER__WARNING("HW Latency measurement is supported only on PCIe devices");
- return make_unexpected(HAILO_INVALID_OPERATION);
- }
-
- size_t h2d_streams_count = 0;
- for (const auto &layer : layers) {
- if (layer.direction == HAILO_D2H_STREAM) {
- if (HAILO_FORMAT_ORDER_HAILO_NMS == layer.format.order) {
- LOGGER__WARNING("HW Latency measurement is not supported on NMS networks");
- return make_unexpected(HAILO_INVALID_OPERATION);
- }
-
- d2h_channel_indexes.insert(layer.index);
- }
- else {
- h2d_streams_count++;
- }
- }
-
- if (h2d_streams_count > 1) {
- LOGGER__WARNING("HW Latency measurement is supported on networks with a single input");
- return make_unexpected(HAILO_INVALID_OPERATION);
- }
-
- return make_shared_nothrow<LatencyMeter>(d2h_channel_indexes, MAX_IRQ_TIMESTAMPS_SIZE);
-}
-
-hailo_status ActivatedNetworkGroupBase::activate_low_level_streams()
+hailo_status ActivatedNetworkGroupBase::activate_low_level_streams(uint16_t dynamic_batch_size)
{
for (auto &name_pair : m_input_streams) {
- auto status = name_pair.second->activate_stream();
+ auto status = name_pair.second->activate_stream(dynamic_batch_size);
CHECK_SUCCESS(status);
}
for (auto &name_pair : m_output_streams) {
- auto status = name_pair.second->activate_stream();
+ auto status = name_pair.second->activate_stream(dynamic_batch_size);
CHECK_SUCCESS(status);
}
return activate(network_group_params);
}
+Expected<std::unique_ptr<ActivatedNetworkGroup>> ConfiguredNetworkGroupBase::activate(
+ const hailo_activate_network_group_params_t &network_group_params)
+{
+ CHECK_AS_EXPECTED(!m_is_scheduling, HAILO_INVALID_OPERATION,
+ "Manually activating a network group is not allowed when the network group scheduler is active!");
+ return activate_internal(network_group_params, CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE);
+}
+
Expected<std::chrono::nanoseconds> get_latency(LatencyMeterPtr &latency_meter, bool clear)
{
auto hw_latency = latency_meter->get_latency(clear);
bool clear = ((m_config_params.latency & HAILO_LATENCY_CLEAR_AFTER_GET) == HAILO_LATENCY_CLEAR_AFTER_GET);
LatencyMeasurementResult result = {};
+ auto latency_meters_exp = get_latnecy_meters();
+ CHECK_EXPECTED(latency_meters_exp);
+ auto latency_meters = latency_meters_exp.release();
+
if (network_name.empty()) {
std::chrono::nanoseconds latency_sum(0);
uint32_t measurements_count = 0;
- for (auto &latency_meter_pair : m_latency_meter) {
+ for (auto &latency_meter_pair : *latency_meters.get()) {
auto hw_latency = get_latency(latency_meter_pair.second, clear);
if (HAILO_NOT_AVAILABLE == hw_latency.status()) {
continue;
}
result.avg_hw_latency = latency_sum / measurements_count;
} else {
- auto partial_network_name = m_network_group_metadata.get_partial_network_name(network_name);
- CHECK_EXPECTED(partial_network_name);
- if(!contains(m_latency_meter, partial_network_name.value())) {
- LOGGER__DEBUG("No latency measurements was found for network {}", partial_network_name.value());
- return make_unexpected(HAILO_NOT_AVAILABLE);
+ if(!contains(*latency_meters, network_name)) {
+ LOGGER__DEBUG("No latency measurements was found for network {}", network_name);
+ return make_unexpected(HAILO_NOT_FOUND);
}
- auto hw_latency = get_latency(m_latency_meter.at(partial_network_name.value()), clear);
+ auto hw_latency = get_latency(latency_meters->at(network_name), clear);
if (HAILO_NOT_AVAILABLE == hw_latency.status()) {
return make_unexpected(HAILO_NOT_AVAILABLE);
}
return result;
}
-
-
Expected<OutputStreamWithParamsVector> ConfiguredNetworkGroupBase::get_output_streams_from_vstream_names(
const std::map<std::string, hailo_vstream_params_t> &outputs_params)
{
ConfiguredNetworkGroupBase::ConfiguredNetworkGroupBase(
const ConfigureNetworkParams &config_params, const uint8_t net_group_index,
const NetworkGroupMetadata &network_group_metadata, hailo_status &status) :
- ConfiguredNetworkGroup::ConfiguredNetworkGroup(),
+ ConfiguredNetworkGroupBase(config_params, net_group_index, network_group_metadata, false, status)
+{}
+
+ConfiguredNetworkGroupBase::ConfiguredNetworkGroupBase(
+ const ConfigureNetworkParams &config_params, const uint8_t net_group_index,
+ const NetworkGroupMetadata &network_group_metadata, bool is_scheduling, hailo_status &status) :
m_config_params(config_params),
+ m_min_configured_batch_size(get_smallest_configured_batch_size(config_params)),
m_net_group_index(net_group_index),
- m_latency_meter(),
m_network_group_metadata(network_group_metadata),
m_activation_time_accumulator(),
- m_deactivation_time_accumulator()
+ m_deactivation_time_accumulator(),
+ m_is_scheduling(is_scheduling)
{
auto event = Event::create_shared(Event::State::not_signalled);
if (nullptr == event) {
status = HAILO_SUCCESS;
}
+uint16_t ConfiguredNetworkGroupBase::get_smallest_configured_batch_size(const ConfigureNetworkParams &config_params)
+{
+ // There are two possible situations:
+ // 1) All networks in the network group have the same configured (and hence smallest) batch_size =>
+ // We return that batch size.
+ // 2) Not all of the networks have the same configured (and hence smallest) batch_size. Currently, when
+ // using dynamic_batch_sizes, all networks will use the same dynamic_batch_size (until HRT-6535 is done).
+ // Hence, we must not set a dynamic_batch_size to a value greater than the smallest configured network
+ // batch_size (e.g. all the resources allocated are for at most the configured network batch_size).
+ return std::min_element(config_params.network_params_by_name.begin(), config_params.network_params_by_name.end(),
+ [](const auto& lhs, const auto& rhs) { return lhs.second.batch_size < rhs.second.batch_size; })->second.batch_size;
+}
+
+Expected<std::unique_ptr<ActivatedNetworkGroup>> ConfiguredNetworkGroupBase::activate_internal(
+ const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size)
+{
+ CHECK_AS_EXPECTED(dynamic_batch_size <= m_min_configured_batch_size, HAILO_INVALID_ARGUMENT,
+ "Dynamic batch size ({}) must be less than/equal to the smallest configured batch size ({})",
+ dynamic_batch_size, m_min_configured_batch_size);
+ return activate_impl(network_group_params, dynamic_batch_size);
+}
+
+Expected<std::unique_ptr<ActivatedNetworkGroup>> ConfiguredNetworkGroupBase::force_activate(uint16_t dynamic_batch_size)
+{
+ return activate_internal(HailoRTDefaults::get_network_group_params(), dynamic_batch_size);
+}
+
const std::string &ConfiguredNetworkGroupBase::get_network_group_name() const
{
return m_network_group_metadata.network_group_name();
CHECK_EXPECTED(layer_infos);
for (const auto &layer_info : layer_infos.release()) {
if (layer_info.name == stream_name) {
- auto partial_network_name = layer_info.partial_network_name;
for (auto const &network_params_pair : m_config_params.network_params_by_name) {
- auto network_name = network_params_pair.first;
- auto found = network_name.find(HAILO_DEFAULT_NETWORK_NAME_QUALIFIER + partial_network_name);
- if (found != std::string::npos) {
+ if (network_params_pair.first == layer_info.network_name) {
auto batch_size = network_params_pair.second.batch_size;
return batch_size;
}
return make_unexpected(HAILO_NOT_FOUND);
}
+const ConfigureNetworkParams ConfiguredNetworkGroupBase::get_config_params() const
+{
+ return m_config_params;
+}
+
hailo_status ConfiguredNetworkGroupBase::create_input_stream_from_config_params(Device &device,
const hailo_stream_parameters_t &stream_params, const std::string &stream_name)
{
auto edge_layer = get_layer_info(stream_name);
CHECK_EXPECTED_AS_STATUS(edge_layer);
- auto partial_network_name = edge_layer->partial_network_name;
- auto latency_meter = (contains(m_latency_meter, partial_network_name)) ? m_latency_meter.at(partial_network_name) : nullptr;
-
CHECK(device.is_stream_interface_supported(stream_params.stream_interface), HAILO_INVALID_OPERATION,
"Device does not supports the given stream interface streams. Please update input_stream_params for stream {}.",
stream_name);
auto batch_size_exp = get_stream_batch_size(stream_name);
CHECK_EXPECTED_AS_STATUS(batch_size_exp);
const auto stream_index = edge_layer->index;
- const auto channel_index = get_boundary_channel_index(stream_index, HAILO_H2D_STREAM, stream_name);
- CHECK_EXPECTED_AS_STATUS(channel_index, "Failed to get channel index for input stream {}", stream_index);
+ auto vdma_channel_ptr = get_boundary_vdma_channel_by_stream_name(stream_name);
+ CHECK_EXPECTED_AS_STATUS(vdma_channel_ptr, "Failed to get vdma channel for output stream {}", stream_index);
- auto input_stream = PcieInputStream::create(device, channel_index.value(),
- edge_layer.value(), batch_size_exp.value(), m_network_group_activated_event, latency_meter);
+ auto input_stream = PcieInputStream::create(device, vdma_channel_ptr.release(),
+ edge_layer.value(), batch_size_exp.value(), m_network_group_activated_event);
CHECK_EXPECTED_AS_STATUS(input_stream);
m_input_streams.insert(make_pair(stream_name, input_stream.release()));
}
auto batch_size_exp = get_stream_batch_size(stream_name);
CHECK_EXPECTED_AS_STATUS(batch_size_exp);
const auto stream_index = edge_layer->index;
- const auto channel_index = get_boundary_channel_index(stream_index, HAILO_H2D_STREAM, stream_name);
- CHECK_EXPECTED_AS_STATUS(channel_index, "Failed to get channel index for input stream {}", stream_index);
+ auto vdma_channel_ptr = get_boundary_vdma_channel_by_stream_name(stream_name);
+ CHECK_EXPECTED_AS_STATUS(vdma_channel_ptr, "Failed to get vdma channel for output stream {}", stream_index);
- auto input_stream = CoreInputStream::create(device, channel_index.value(),
- edge_layer.value(), batch_size_exp.value(), m_network_group_activated_event, latency_meter);
+ auto input_stream = CoreInputStream::create(device, vdma_channel_ptr.release(),
+ edge_layer.value(), batch_size_exp.value(), m_network_group_activated_event);
CHECK_EXPECTED_AS_STATUS(input_stream);
m_input_streams.insert(make_pair(stream_name, input_stream.release()));
}
auto edge_layer = get_layer_info(stream_name);
CHECK_EXPECTED_AS_STATUS(edge_layer);
- auto partial_network_name = edge_layer->partial_network_name;
- auto latency_meter = (contains(m_latency_meter, partial_network_name)) ? m_latency_meter.at(partial_network_name) : nullptr;
-
CHECK(device.is_stream_interface_supported(stream_params.stream_interface), HAILO_INVALID_OPERATION,
"Device does not supports the given stream interface streams. Please update input_stream_params for stream {}.",
stream_name);
auto batch_size_exp = get_stream_batch_size(stream_name);
CHECK_EXPECTED_AS_STATUS(batch_size_exp);
const auto stream_index = edge_layer->index;
- const auto channel_index = get_boundary_channel_index(stream_index, HAILO_D2H_STREAM, stream_name);
- CHECK_EXPECTED_AS_STATUS(channel_index, "Failed to get channel index for output stream {}", stream_index);
+ auto vdma_channel_ptr = get_boundary_vdma_channel_by_stream_name(stream_name);
+ CHECK_EXPECTED_AS_STATUS(vdma_channel_ptr, "Failed to get vdma channel for output stream {}", stream_index);
- auto output_stream = PcieOutputStream::create(device, channel_index.value(),
- edge_layer.value(), batch_size_exp.value(), m_network_group_activated_event, latency_meter);
+ auto output_stream = PcieOutputStream::create(device, vdma_channel_ptr.release(),
+ edge_layer.value(), batch_size_exp.value(), m_network_group_activated_event);
CHECK_EXPECTED_AS_STATUS(output_stream);
m_output_streams.insert(make_pair(stream_name, output_stream.release()));
}
auto batch_size_exp = get_stream_batch_size(stream_name);
CHECK_EXPECTED_AS_STATUS(batch_size_exp);
const auto stream_index = edge_layer->index;
- const auto channel_index = get_boundary_channel_index(stream_index, HAILO_D2H_STREAM, stream_name);
- CHECK_EXPECTED_AS_STATUS(channel_index, "Failed to get channel index for output stream {}", stream_index);
+ auto vdma_channel_ptr = get_boundary_vdma_channel_by_stream_name(stream_name);
+ CHECK_EXPECTED_AS_STATUS(vdma_channel_ptr, "Failed to get vdma channel for output stream {}", stream_index);
- auto output_stream = CoreOutputStream::create(device, channel_index.value(),
- edge_layer.value(), batch_size_exp.value(), m_network_group_activated_event,
- latency_meter);
+ auto output_stream = CoreOutputStream::create(device, vdma_channel_ptr.release(),
+ edge_layer.value(), batch_size_exp.value(), m_network_group_activated_event);
CHECK_EXPECTED_AS_STATUS(output_stream);
m_output_streams.insert(make_pair(stream_name, output_stream.release()));
}
hailo_status ConfiguredNetworkGroupBase::create_streams_from_config_params(Device &device)
{
- if ((m_config_params.latency & HAILO_LATENCY_MEASURE) == HAILO_LATENCY_MEASURE) {
- // Best affort for starting latency meter.
- auto networks_names = m_network_group_metadata.get_partial_network_names();
- for (auto &network_name : networks_names) {
- auto layer_infos = m_network_group_metadata.get_all_layer_infos(network_name);
- CHECK_EXPECTED_AS_STATUS(layer_infos);
- auto latency_meter = ConfiguredNetworkGroupBase::create_hw_latency_meter(device, layer_infos.value());
- if (latency_meter) {
- m_latency_meter.emplace(network_name, latency_meter.release());
- LOGGER__DEBUG("Starting hw latency measurement for network {}", network_name);
- }
- }
- }
-
for (const auto &stream_parameters_pair : m_config_params.stream_params_by_name) {
switch (stream_parameters_pair.second.direction) {
case HAILO_H2D_STREAM:
Expected<InputStreamRefVector> ConfiguredNetworkGroupBase::get_input_streams_by_network(const std::string &network_name)
{
- auto partial_network_name = m_network_group_metadata.get_partial_network_name(network_name);
- CHECK_EXPECTED(partial_network_name);
-
- auto input_stream_infos = m_network_group_metadata.get_input_stream_infos(partial_network_name.value());
+ auto input_stream_infos = m_network_group_metadata.get_input_stream_infos(network_name);
CHECK_EXPECTED(input_stream_infos);
InputStreamRefVector result;
Expected<OutputStreamRefVector> ConfiguredNetworkGroupBase::get_output_streams_by_network(const std::string &network_name)
{
- auto partial_network_name = m_network_group_metadata.get_partial_network_name(network_name);
- CHECK_EXPECTED(partial_network_name);
-
- auto output_stream_infos = m_network_group_metadata.get_output_stream_infos(partial_network_name.value());
+ auto output_stream_infos = m_network_group_metadata.get_output_stream_infos(network_name);
CHECK_EXPECTED(output_stream_infos);
OutputStreamRefVector result;
bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size,
const std::string &network_name)
{
- auto partial_network_name = m_network_group_metadata.get_partial_network_name(network_name);
- CHECK_EXPECTED(partial_network_name);
-
- auto input_vstream_infos = m_network_group_metadata.get_input_vstream_infos(partial_network_name.value());
+ auto input_vstream_infos = m_network_group_metadata.get_input_vstream_infos(network_name);
CHECK_EXPECTED(input_vstream_infos);
std::map<std::string, hailo_vstream_params_t> res;
bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size,
const std::string &network_name)
{
- auto partial_network_name = m_network_group_metadata.get_partial_network_name(network_name);
- CHECK_EXPECTED(partial_network_name);
-
- auto output_vstream_infos = m_network_group_metadata.get_output_vstream_infos(partial_network_name.value());
+ auto output_vstream_infos = m_network_group_metadata.get_output_vstream_infos(network_name);
CHECK_EXPECTED(output_vstream_infos);
std::map<std::string, hailo_vstream_params_t> res;
Expected<std::vector<hailo_stream_info_t>> ConfiguredNetworkGroupBase::get_all_stream_infos(
const std::string &network_name) const
{
- auto partial_network_name = m_network_group_metadata.get_partial_network_name(network_name);
- CHECK_EXPECTED(partial_network_name);
-
- return m_network_group_metadata.get_all_stream_infos(partial_network_name.value());
+ return m_network_group_metadata.get_all_stream_infos(network_name);
}
Expected<std::vector<hailo_vstream_info_t>> ConfiguredNetworkGroupBase::get_input_vstream_infos(
const std::string &network_name) const
{
- auto partial_network_name = m_network_group_metadata.get_partial_network_name(network_name);
- CHECK_EXPECTED(partial_network_name);
-
- return m_network_group_metadata.get_input_vstream_infos(partial_network_name.value());
+ return m_network_group_metadata.get_input_vstream_infos(network_name);
}
Expected<std::vector<hailo_vstream_info_t>> ConfiguredNetworkGroupBase::get_output_vstream_infos(
const std::string &network_name) const
{
- auto partial_network_name = m_network_group_metadata.get_partial_network_name(network_name);
- CHECK_EXPECTED(partial_network_name);
-
- return m_network_group_metadata.get_output_vstream_infos(partial_network_name.value());
+ return m_network_group_metadata.get_output_vstream_infos(network_name);
}
Expected<std::vector<hailo_vstream_info_t>> ConfiguredNetworkGroupBase::get_all_vstream_infos(
const std::string &network_name) const
{
- auto partial_network_name = m_network_group_metadata.get_partial_network_name(network_name);
- CHECK_EXPECTED(partial_network_name);
-
- return m_network_group_metadata.get_all_vstream_infos(partial_network_name.value());
+ return m_network_group_metadata.get_all_vstream_infos(network_name);
}
AccumulatorPtr ConfiguredNetworkGroupBase::get_activation_time_accumulator() const
/**
* @file network_group_internal.hpp
* @brief Class declaration for ConfiguredNetworkGroupBase and ActivatedNetworkGroupBase that implement the basic ConfiguredNetworkGroup
- * and ActivatedNetworkGroup interfaces. All internal classes that are relavant should inherit from the
+ * and ActivatedNetworkGroup interfaces. All internal classes that are relevant should inherit from the
* ConfiguredNetworkGroupBase and ActivatedNetworkGroupBase classes.
- * Hence, the hiearchy is as follows:
+ * Hence, the hierarchy is as follows:
* -----------------------------------------------------------------------------
- * | ConfiguredNetworkGroup | (External "interface")
- * | | |
- * | ConfiguredNetworkGroupBase | (Base classes)
- * | / \ |
- * | VdmaConfigNetworkGroup HcpConfigNetworkGroup | (Actual implementations)
+ * | ConfiguredNetworkGroup | (External "interface")
+ * | ________________|___________________ |
+ * | / \ |
+ * | ConfiguredNetworkGroupBase ConfiguredNetworkGroupWrapper | (Base classes)
+ * | / \ |
+ * | VdmaConfigNetworkGroup HcpConfigNetworkGroup | (Actual implementations)
* -----------------------------------------------------------------------------
* | ActivatedNetworkGroup | (External "interface")
* | | |
#include "hailo/network_group.hpp"
#include "hef_internal.hpp"
#include "common/latency_meter.hpp"
+#include "control_protocol.h"
+#include "vdma_channel.hpp"
namespace hailort
{
hailo_activate_network_group_params_t m_network_group_params;
ActivatedNetworkGroupBase(const hailo_activate_network_group_params_t &network_group_params,
+ uint16_t dynamic_batch_size,
std::map<std::string, std::unique_ptr<InputStream>> &input_streams,
std::map<std::string, std::unique_ptr<OutputStream>> &output_streams,
EventPtr &&network_group_activated_event, hailo_status &status);
private:
- hailo_status activate_low_level_streams();
+ hailo_status activate_low_level_streams(uint16_t dynamic_batch_size);
hailo_status validate_network_group_params(const hailo_activate_network_group_params_t &network_group_params);
std::map<std::string, std::unique_ptr<InputStream>> &m_input_streams;
ConfiguredNetworkGroupBase &operator=(ConfiguredNetworkGroupBase &&other) = delete;
ConfiguredNetworkGroupBase(ConfiguredNetworkGroupBase &&other) = default;
+ Expected<std::unique_ptr<ActivatedNetworkGroup>> force_activate(
+ uint16_t dynamic_batch_size = CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE);
+ virtual Expected<std::unique_ptr<ActivatedNetworkGroup>> activate(const hailo_activate_network_group_params_t &network_group_params) override;
virtual hailo_status wait_for_activation(const std::chrono::milliseconds &timeout) override;
virtual const std::string &get_network_group_name() const override;
Expected<uint16_t> get_stream_batch_size(const std::string &stream_name);
+ const ConfigureNetworkParams get_config_params() const;
+
protected:
ConfiguredNetworkGroupBase(const ConfigureNetworkParams &config_params, const uint8_t m_net_group_index,
const NetworkGroupMetadata &network_group_metadata, hailo_status &status);
+ ConfiguredNetworkGroupBase(const ConfigureNetworkParams &config_params, const uint8_t m_net_group_index,
+ const NetworkGroupMetadata &network_group_metadata, bool is_scheduling, hailo_status &status);
+
+ virtual Expected<std::unique_ptr<ActivatedNetworkGroup>> activate_internal(
+ const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) override;
+ virtual Expected<std::unique_ptr<ActivatedNetworkGroup>> activate_impl(
+ const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) = 0;
hailo_status create_output_stream_from_config_params(Device &device,
const hailo_stream_parameters_t &stream_params, const std::string &stream_name);
virtual Expected<uint8_t> get_boundary_channel_index(uint8_t stream_index, hailo_stream_direction_t direction,
const std::string &layer_name) = 0;
+ virtual Expected<std::shared_ptr<LatencyMetersMap>> get_latnecy_meters() = 0;
+ virtual Expected<std::shared_ptr<VdmaChannel>> get_boundary_vdma_channel_by_stream_name(const std::string &stream_name) = 0;
const ConfigureNetworkParams m_config_params;
+ const uint16_t m_min_configured_batch_size; // TODO: remove after HRT-6535
uint8_t m_net_group_index;
- std::map<std::string, LatencyMeterPtr> m_latency_meter; // Latency meter per network
std::map<std::string, std::unique_ptr<InputStream>> m_input_streams;
std::map<std::string, std::unique_ptr<OutputStream>> m_output_streams;
EventPtr m_network_group_activated_event;
const NetworkGroupMetadata m_network_group_metadata;
AccumulatorPtr m_activation_time_accumulator;
AccumulatorPtr m_deactivation_time_accumulator;
+
+private:
+ friend class ConfiguredNetworkGroupWrapper;
+
+ static uint16_t get_smallest_configured_batch_size(const ConfigureNetworkParams &config_params);
+
+ bool m_is_scheduling;
};
} /* namespace hailort */
--- /dev/null
+/**
+ * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file network_group_wrapper.cpp
+ * @brief: Network Group Wrapper
+ **/
+
+#include "network_group_wrapper.hpp"
+
+namespace hailort
+{
+
+const std::string &ConfiguredNetworkGroupWrapper::get_network_group_name() const
+{
+ return m_configured_network_group->get_network_group_name();
+}
+
+Expected<hailo_stream_interface_t> ConfiguredNetworkGroupWrapper::get_default_streams_interface()
+{
+ return m_configured_network_group->get_default_streams_interface();
+}
+
+std::vector<std::reference_wrapper<InputStream>> ConfiguredNetworkGroupWrapper::get_input_streams_by_interface(hailo_stream_interface_t stream_interface)
+{
+ return m_configured_network_group->get_input_streams_by_interface(stream_interface);
+}
+
+std::vector<std::reference_wrapper<OutputStream>> ConfiguredNetworkGroupWrapper::get_output_streams_by_interface(hailo_stream_interface_t stream_interface)
+{
+ return m_configured_network_group->get_output_streams_by_interface(stream_interface);
+}
+
+ExpectedRef<InputStream> ConfiguredNetworkGroupWrapper::get_input_stream_by_name(const std::string& name)
+{
+ return m_configured_network_group->get_input_stream_by_name(name);
+}
+ExpectedRef<OutputStream> ConfiguredNetworkGroupWrapper::get_output_stream_by_name(const std::string& name)
+{
+ return m_configured_network_group->get_output_stream_by_name(name);
+}
+
+Expected<InputStreamRefVector> ConfiguredNetworkGroupWrapper::get_input_streams_by_network(const std::string &network_name)
+{
+ return m_configured_network_group->get_input_streams_by_network(network_name);
+}
+
+Expected<OutputStreamRefVector> ConfiguredNetworkGroupWrapper::get_output_streams_by_network(const std::string &network_name)
+{
+ return m_configured_network_group->get_output_streams_by_network(network_name);
+}
+
+InputStreamRefVector ConfiguredNetworkGroupWrapper::get_input_streams()
+{
+ return m_configured_network_group->get_input_streams();
+}
+
+OutputStreamRefVector ConfiguredNetworkGroupWrapper::get_output_streams()
+{
+ return m_configured_network_group->get_output_streams();
+}
+
+Expected<LatencyMeasurementResult> ConfiguredNetworkGroupWrapper::get_latency_measurement(const std::string &network_name)
+{
+ return m_configured_network_group->get_latency_measurement(network_name);
+}
+
+Expected<OutputStreamWithParamsVector> ConfiguredNetworkGroupWrapper::get_output_streams_from_vstream_names(
+ const std::map<std::string, hailo_vstream_params_t> &outputs_params)
+{
+ return m_configured_network_group->get_output_streams_from_vstream_names(outputs_params);
+}
+
+Expected<std::unique_ptr<ActivatedNetworkGroup>> ConfiguredNetworkGroupWrapper::activate_internal(const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size)
+{
+ return m_configured_network_group->activate_internal(network_group_params, dynamic_batch_size);
+}
+
+hailo_status ConfiguredNetworkGroupWrapper::wait_for_activation(const std::chrono::milliseconds &timeout)
+{
+ return m_configured_network_group->wait_for_activation(timeout);
+}
+
+Expected<std::map<std::string, hailo_vstream_params_t>> ConfiguredNetworkGroupWrapper::make_input_vstream_params(
+ bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size,
+ const std::string &network_name)
+{
+ return m_configured_network_group->make_input_vstream_params(quantized, format_type, timeout_ms, queue_size, network_name);
+}
+Expected<std::map<std::string, hailo_vstream_params_t>> ConfiguredNetworkGroupWrapper::make_output_vstream_params(
+ bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size,
+ const std::string &network_name)
+{
+ return m_configured_network_group->make_output_vstream_params(quantized, format_type, timeout_ms, queue_size, network_name);
+}
+
+Expected<std::vector<std::map<std::string, hailo_vstream_params_t>>> ConfiguredNetworkGroupWrapper::make_output_vstream_params_groups(
+ bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size)
+{
+ return m_configured_network_group->make_output_vstream_params_groups(quantized, format_type, timeout_ms, queue_size);
+}
+
+Expected<std::vector<std::vector<std::string>>> ConfiguredNetworkGroupWrapper::get_output_vstream_groups()
+{
+ return m_configured_network_group->get_output_vstream_groups();
+}
+
+Expected<std::vector<hailo_network_info_t>> ConfiguredNetworkGroupWrapper::get_network_infos() const
+{
+ return m_configured_network_group->get_network_infos();
+}
+
+Expected<std::vector<hailo_stream_info_t>> ConfiguredNetworkGroupWrapper::get_all_stream_infos(const std::string &network_name) const
+{
+ return m_configured_network_group->get_all_stream_infos(network_name);
+}
+
+Expected<std::vector<hailo_vstream_info_t>> ConfiguredNetworkGroupWrapper::get_input_vstream_infos(const std::string &network_name) const
+{
+ return m_configured_network_group->get_input_vstream_infos(network_name);
+}
+
+Expected<std::vector<hailo_vstream_info_t>> ConfiguredNetworkGroupWrapper::get_output_vstream_infos(const std::string &network_name) const
+{
+ return m_configured_network_group->get_output_vstream_infos(network_name);
+}
+
+Expected<std::vector<hailo_vstream_info_t>> ConfiguredNetworkGroupWrapper::get_all_vstream_infos(const std::string &network_name) const
+{
+ return m_configured_network_group->get_all_vstream_infos(network_name);
+}
+
+hailo_status ConfiguredNetworkGroupWrapper::set_scheduler_timeout(const std::chrono::milliseconds &timeout, const std::string &network_name)
+{
+ return m_configured_network_group->set_scheduler_timeout(timeout, network_name);
+}
+hailo_status ConfiguredNetworkGroupWrapper::set_scheduler_threshold(uint32_t threshold, const std::string &network_name)
+{
+ return m_configured_network_group->set_scheduler_threshold(threshold, network_name);
+}
+
+AccumulatorPtr ConfiguredNetworkGroupWrapper::get_activation_time_accumulator() const
+{
+ return m_configured_network_group->get_activation_time_accumulator();
+}
+
+AccumulatorPtr ConfiguredNetworkGroupWrapper::get_deactivation_time_accumulator() const
+{
+ return m_configured_network_group->get_deactivation_time_accumulator();
+}
+
+std::shared_ptr<ConfiguredNetworkGroupBase> ConfiguredNetworkGroupWrapper::get_configured_network() const
+{
+ return m_configured_network_group;
+}
+
+ConfiguredNetworkGroupWrapper::ConfiguredNetworkGroupWrapper(std::shared_ptr<ConfiguredNetworkGroupBase> configured_network_group) :
+ m_configured_network_group(configured_network_group)
+{}
+
+Expected<ConfiguredNetworkGroupWrapper> ConfiguredNetworkGroupWrapper::create(std::shared_ptr<ConfiguredNetworkGroupBase> configured_network_group)
+{
+ return ConfiguredNetworkGroupWrapper(configured_network_group);
+}
+
+Expected<ConfiguredNetworkGroupWrapper> ConfiguredNetworkGroupWrapper::clone()
+{
+ auto wrapper = create(m_configured_network_group);
+ CHECK_EXPECTED(wrapper);
+
+ return wrapper;
+}
+
+Expected<std::unique_ptr<ActivatedNetworkGroup>> ConfiguredNetworkGroupWrapper::activate(const hailo_activate_network_group_params_t &network_group_params)
+{
+ return m_configured_network_group->activate(network_group_params);
+}
+
+} /* namespace hailort */
--- /dev/null
+/**
+ * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file network_group_wrapper.hpp
+ * @brief Class declaration for ConfiguredNetworkGroupWrapper, a wrapper around ConfiguredNetworkGroupBase which is used
+ * to support multiple ConfiguredNetworkGroup objects that encapsulate the same actual configured network group.
+ **/
+
+#ifndef _HAILO_NETWORK_GROUP_WRAPPER_HPP_
+#define _HAILO_NETWORK_GROUP_WRAPPER_HPP_
+
+#include "hailo/hailort.h"
+#include "hailo/network_group.hpp"
+#include "network_group_internal.hpp"
+
+namespace hailort
+{
+
+class ConfiguredNetworkGroupWrapper : public ConfiguredNetworkGroup
+{
+public:
+ virtual ~ConfiguredNetworkGroupWrapper() = default;
+ ConfiguredNetworkGroupWrapper(const ConfiguredNetworkGroupWrapper &other) = delete;
+ ConfiguredNetworkGroupWrapper &operator=(const ConfiguredNetworkGroupWrapper &other) = delete;
+ ConfiguredNetworkGroupWrapper &operator=(ConfiguredNetworkGroupWrapper &&other) = delete;
+ ConfiguredNetworkGroupWrapper(ConfiguredNetworkGroupWrapper &&other) = default;
+
+ static Expected<ConfiguredNetworkGroupWrapper> create(std::shared_ptr<ConfiguredNetworkGroupBase> configured_network_group);
+ Expected<ConfiguredNetworkGroupWrapper> clone();
+
+ virtual const std::string &get_network_group_name() const override;
+ virtual Expected<hailo_stream_interface_t> get_default_streams_interface() override;
+
+ virtual std::vector<std::reference_wrapper<InputStream>> get_input_streams_by_interface(hailo_stream_interface_t stream_interface) override;
+ virtual std::vector<std::reference_wrapper<OutputStream>> get_output_streams_by_interface(hailo_stream_interface_t stream_interface) override;
+ virtual ExpectedRef<InputStream> get_input_stream_by_name(const std::string& name) override;
+ virtual ExpectedRef<OutputStream> get_output_stream_by_name(const std::string& name) override;
+ virtual Expected<InputStreamRefVector> get_input_streams_by_network(const std::string &network_name="") override;
+ virtual Expected<OutputStreamRefVector> get_output_streams_by_network(const std::string &network_name="") override;
+ virtual InputStreamRefVector get_input_streams() override;
+ virtual OutputStreamRefVector get_output_streams() override;
+ virtual Expected<LatencyMeasurementResult> get_latency_measurement(const std::string &network_name="") override;
+ virtual Expected<OutputStreamWithParamsVector> get_output_streams_from_vstream_names(
+ const std::map<std::string, hailo_vstream_params_t> &outputs_params) override;
+
+ virtual Expected<std::unique_ptr<ActivatedNetworkGroup>> activate(const hailo_activate_network_group_params_t &network_group_params) override;
+ virtual hailo_status wait_for_activation(const std::chrono::milliseconds &timeout) override;
+
+ virtual Expected<std::map<std::string, hailo_vstream_params_t>> make_input_vstream_params(
+ bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size,
+ const std::string &network_name="") override;
+ virtual Expected<std::map<std::string, hailo_vstream_params_t>> make_output_vstream_params(
+ bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size,
+ const std::string &network_name="") override;
+ virtual Expected<std::vector<std::map<std::string, hailo_vstream_params_t>>> make_output_vstream_params_groups(
+ bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size) override;
+ virtual Expected<std::vector<std::vector<std::string>>> get_output_vstream_groups() override;
+
+ virtual Expected<std::vector<hailo_network_info_t>> get_network_infos() const override;
+ virtual Expected<std::vector<hailo_stream_info_t>> get_all_stream_infos(const std::string &network_name="") const override;
+ virtual Expected<std::vector<hailo_vstream_info_t>> get_input_vstream_infos(const std::string &network_name="") const override;
+ virtual Expected<std::vector<hailo_vstream_info_t>> get_output_vstream_infos(const std::string &network_name="") const override;
+ virtual Expected<std::vector<hailo_vstream_info_t>> get_all_vstream_infos(const std::string &network_name="") const override;
+
+ virtual hailo_status set_scheduler_timeout(const std::chrono::milliseconds &timeout, const std::string &network_name) override;
+ virtual hailo_status set_scheduler_threshold(uint32_t threshold, const std::string &network_name) override;
+
+ virtual AccumulatorPtr get_activation_time_accumulator() const override;
+ virtual AccumulatorPtr get_deactivation_time_accumulator() const override;
+
+ std::shared_ptr<ConfiguredNetworkGroupBase> get_configured_network() const;
+
+protected:
+ virtual Expected<std::unique_ptr<ActivatedNetworkGroup>> activate_internal(
+ const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) override;
+
+private:
+ ConfiguredNetworkGroupWrapper(std::shared_ptr<ConfiguredNetworkGroupBase> configured_network_group);
+
+ std::shared_ptr<ConfiguredNetworkGroupBase> m_configured_network_group;
+};
+
+}
+
+#endif /* _HAILO_NETWORK_GROUP_WRAPPER_HPP_ */
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file pipeline_multiplexer.cpp
+ * @brief: Pipeline Multiplexer
+ **/
+
+#include "pipeline_multiplexer.hpp"
+#include "common/utils.hpp"
+
+namespace hailort
+{
+
+PipelineMultiplexer::PipelineMultiplexer() :
+ m_is_enabled(false),
+ m_mutex(),
+ m_readers(),
+ m_write_mutex()
+{}
+
+hailo_status PipelineMultiplexer::add_reader(EventPtr &reader_event)
+{
+ std::unique_lock<std::mutex> lock(m_mutex);
+
+ auto was_empty = m_readers.empty();
+ m_readers.push(reader_event);
+ if (was_empty) {
+ auto status = reader_event->signal();
+ CHECK_SUCCESS(status);
+ }
+
+ return HAILO_SUCCESS;
+}
+
+hailo_status PipelineMultiplexer::signal_done_reading()
+{
+ std::unique_lock<std::mutex> lock(m_mutex);
+
+ if (m_readers.empty()) {
+ return HAILO_INTERNAL_FAILURE;
+ }
+ m_readers.front()->reset();
+ m_readers.pop();
+
+ if (!m_readers.empty()) {
+ m_readers.front()->signal();
+ }
+
+ return HAILO_SUCCESS;
+}
+
+void PipelineMultiplexer::enable()
+{
+ m_is_enabled = true;
+}
+
+bool PipelineMultiplexer::is_enabled() const
+{
+ return m_is_enabled;
+}
+
+void PipelineMultiplexer::acquire_write_lock()
+{
+ m_write_mutex.lock();
+}
+
+void PipelineMultiplexer::release_write_lock()
+{
+ m_write_mutex.unlock();
+}
+
+} /* namespace hailort */
--- /dev/null
+/**
+ * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file pipeline_multiplexer.hpp
+ * @brief The pipeline multiplexer is a synchronization mechanism that allows communication
+ * between different pipelines that use the same low-level streams.
+ **/
+
+#ifndef _HAILO_PIPELINE_MULTIPLEXER_HPP_
+#define _HAILO_PIPELINE_MULTIPLEXER_HPP_
+
+#include "hailo/event.hpp"
+
+#include <queue>
+#include <mutex>
+
+namespace hailort
+{
+
+class PipelineMultiplexer
+{
+public:
+ virtual ~PipelineMultiplexer() = default;
+ PipelineMultiplexer(const PipelineMultiplexer &other) = delete;
+ PipelineMultiplexer &operator=(const PipelineMultiplexer &other) = delete;
+ PipelineMultiplexer &operator=(PipelineMultiplexer &&other) = delete;
+ PipelineMultiplexer(PipelineMultiplexer &&other) = delete;
+
+ PipelineMultiplexer();
+
+ hailo_status add_reader(EventPtr &reader_event);
+ hailo_status signal_done_reading();
+
+ void enable();
+ bool is_enabled() const;
+
+ void acquire_write_lock();
+ void release_write_lock();
+
+private:
+ bool m_is_enabled;
+ std::mutex m_mutex;
+ std::queue<EventPtr> m_readers;
+
+ std::mutex m_write_mutex;
+};
+
+} /* namespace hailort */
+
+#endif /* _HAILO_PIPELINE_MULTIPLEXER_HPP_ */
namespace hailort
{
-
-ConfigResources::ConfigResources(HailoRTDriver &driver, VdmaBuffer &&buffer,
- VdmaDescriptorList &&descriptor, uint16_t requested_desc_page_size, size_t total_buffer_size)
- : m_buffer(std::move(buffer)), m_descriptor(std::move(descriptor)),
- m_desc_page_size(driver.calc_desc_page_size(requested_desc_page_size)),
- m_total_buffer_size(total_buffer_size), m_acc_buffer_offset(0), m_acc_desc_count(0),
- m_current_buffer_size(0)
-{}
-
-Expected<uint16_t> ConfigResources::program_descriptors()
-{
- auto descriptors_count =
- m_descriptor.program_descriptors(m_acc_buffer_offset, VdmaInterruptsDomain::NONE, VdmaInterruptsDomain::DEVICE,
- m_acc_desc_count, false);
- CHECK_EXPECTED(descriptors_count);
-
- /* TODO - remove static cast */
- m_acc_desc_count = static_cast<uint16_t>(m_acc_desc_count + descriptors_count.value());
- m_acc_buffer_offset = 0;
-
- return descriptors_count;
-}
-
-hailo_status ConfigResources::write(const void *data, size_t data_size)
-{
- size_t total_offset = (m_acc_desc_count * m_desc_page_size) + m_acc_buffer_offset;
- auto status = m_buffer.write(data, data_size, total_offset);
- CHECK_SUCCESS(status);
-
- m_acc_buffer_offset += data_size;
- m_current_buffer_size += data_size;
- return HAILO_SUCCESS;
-}
-
-uint16_t ConfigResources::get_page_size()
-{
- return m_desc_page_size;
-}
-
-size_t ConfigResources::get_total_cfg_size()
-{
- return m_total_buffer_size;
-}
-
-size_t ConfigResources::get_current_buffer_size()
-{
- return m_current_buffer_size;
-}
-
-Expected<ConfigResources> ResourcesManager::create_config_resources(uint8_t channel_index,
- const std::vector<uint32_t> &cfg_sizes, HailoRTDriver &driver)
-{
- auto desc_sizes_pair = VdmaDescriptorList::get_desc_buffer_sizes_for_multiple_transfers(driver, 1, cfg_sizes);
- CHECK_EXPECTED(desc_sizes_pair);
-
- auto page_size = desc_sizes_pair->first;
- auto descs_count = desc_sizes_pair->second;
-
- auto buffer_size = std::accumulate(cfg_sizes.begin(), cfg_sizes.end(), 0);
-
- auto buffer = VdmaBuffer::create((page_size * descs_count), HailoRTDriver::DmaDirection::H2D, driver);
- CHECK_EXPECTED(buffer);
-
- auto desc_list = VdmaDescriptorList::create(descs_count, page_size, driver);
- CHECK_EXPECTED(desc_list);
-
- auto status = desc_list->configure_to_use_buffer(buffer.value(), channel_index);
- CHECK_SUCCESS_AS_EXPECTED(status);
-
- return ConfigResources(driver, buffer.release(), desc_list.release(), page_size, buffer_size);
-}
-
static Expected<std::vector<std::string>> build_network_index_map(ProtoHEFNetworkGroupPtr network_group_proto,
const NetworkGroupSupportedFeatures &supported_features)
{
- std::vector<std::string> partial_network_name_vector;
+ std::vector<std::string> network_names_vector;
if (supported_features.multi_network_support) {
auto network_count = network_group_proto.get()->networks_names_size();
CHECK_AS_EXPECTED((network_count > 0), HAILO_INTERNAL_FAILURE,
"Hef support multiple networks, but no networks found in the proto");
- partial_network_name_vector.reserve(network_count);
+ network_names_vector.reserve(network_count);
for (uint8_t network_index = 0; network_index < network_count; network_index++) {
auto partial_network_name = network_group_proto.get()->networks_names(network_index);
- partial_network_name_vector.push_back(partial_network_name);
+ auto network_name = HefUtils::get_network_name(*network_group_proto, partial_network_name);
+ network_names_vector.push_back(network_name);
}
} else {
/* In case there is no defines networks, add single network with the same name as the network group */
- partial_network_name_vector.reserve(1);
+ network_names_vector.reserve(1);
auto net_group_name = network_group_proto->network_group_metadata().network_group_name();
- auto partial_network_name = HailoRTDefaults::get_partial_network_name();
- partial_network_name_vector.push_back(partial_network_name);
+ network_names_vector.push_back(HailoRTDefaults::get_network_name(net_group_name));
}
- return partial_network_name_vector;
+ return network_names_vector;
+}
+
+static Expected<LatencyMeterPtr> create_hw_latency_meter(const std::vector<LayerInfo> &layers)
+{
+ std::set<uint32_t> d2h_channel_indexes;
+
+ size_t h2d_streams_count = 0;
+ for (const auto &layer : layers) {
+ if (layer.direction == HAILO_D2H_STREAM) {
+ if (HAILO_FORMAT_ORDER_HAILO_NMS == layer.format.order) {
+ LOGGER__WARNING("HW Latency measurement is not supported on NMS networks");
+ return make_unexpected(HAILO_INVALID_OPERATION);
+ }
+
+ d2h_channel_indexes.insert(layer.index);
+ }
+ else {
+ h2d_streams_count++;
+ }
+ }
+
+ if (h2d_streams_count > 1) {
+ LOGGER__WARNING("HW Latency measurement is supported on networks with a single input");
+ return make_unexpected(HAILO_INVALID_OPERATION);
+ }
+
+ return make_shared_nothrow<LatencyMeter>(d2h_channel_indexes, MAX_IRQ_TIMESTAMPS_SIZE);
+}
+
+static Expected<LatencyMetersMap> create_latency_meters_from_config_params(
+ const ConfigureNetworkParams &config_params, std::shared_ptr<NetworkGroupMetadata> network_group_metadata)
+{
+ LatencyMetersMap latency_meters_map;
+
+ if ((config_params.latency & HAILO_LATENCY_MEASURE) == HAILO_LATENCY_MEASURE) {
+ // Best affort for starting latency meter.
+ auto networks_names = network_group_metadata->get_network_names();
+ for (auto &network_name : networks_names) {
+ auto layer_infos = network_group_metadata->get_all_layer_infos(network_name);
+ CHECK_EXPECTED(layer_infos);
+ auto latency_meter = create_hw_latency_meter(layer_infos.value());
+ if (latency_meter) {
+ latency_meters_map.emplace(network_name, latency_meter.release());
+ LOGGER__DEBUG("Starting hw latency measurement for network {}", network_name);
+ }
+ }
+ }
+
+ return latency_meters_map;
}
Expected<ResourcesManager> ResourcesManager::create(VdmaDevice &vdma_device, HailoRTDriver &driver,
uint8_t cfg_channels_count = (0 == network_group_proto->network_group_metadata().cfg_channels_count()) ?
1u : static_cast<uint8_t>(network_group_proto->network_group_metadata().cfg_channels_count());
- std::vector<ConfigResources> preliminary_configs_vector;
+ std::vector<ConfigBuffer> preliminary_configs_vector;
auto cfg_count_preliminary = parsing_info.cfg_infos_preliminary_config.size();
CHECK_AS_EXPECTED(cfg_channels_count >= cfg_count_preliminary, HAILO_INTERNAL_FAILURE,
"preliminary cfg count ({}) is bigger than the size passed to the network_group ({})",
for (uint8_t cfg_index = MIN_H2D_CHANNEL_INDEX; cfg_index < cfg_count_preliminary; cfg_index++) {
CHECK_AS_EXPECTED(contains(parsing_info.cfg_infos_preliminary_config, cfg_index), HAILO_INTERNAL_FAILURE,
"Mismmatch for cfg index {}", cfg_index);
- auto buffer_resource = ResourcesManager::create_config_resources(cfg_index,
- parsing_info.cfg_infos_preliminary_config.at(cfg_index), driver);
+ auto buffer_resource = ConfigBuffer::create(driver, cfg_index,
+ parsing_info.cfg_infos_preliminary_config.at(cfg_index));
CHECK_EXPECTED(buffer_resource);
preliminary_configs_vector.emplace_back(buffer_resource.release());
}
- std::vector<std::vector<ConfigResources>> dynamic_cfg_vectors;
+ std::vector<std::vector<ConfigBuffer>> dynamic_cfg_vectors;
dynamic_cfg_vectors.reserve(network_group_proto->contexts_size());
for (int ctxt_index = 0; ctxt_index < network_group_proto->contexts_size(); ctxt_index++) {
- std::vector<ConfigResources> dynamic_cfg_vector_per_context;
+ std::vector<ConfigBuffer> dynamic_cfg_vector_per_context;
auto cfg_count_ctxt = parsing_info.cfg_infos_per_context[ctxt_index].size();
CHECK_AS_EXPECTED(cfg_channels_count >= cfg_count_ctxt, HAILO_INTERNAL_FAILURE,
for (uint8_t cfg_index = MIN_H2D_CHANNEL_INDEX; cfg_index < cfg_count_ctxt; cfg_index++) {
CHECK_AS_EXPECTED(contains(parsing_info.cfg_infos_per_context[ctxt_index], cfg_index),
HAILO_INTERNAL_FAILURE, "Mismmatch for cfg index {}", cfg_index);
- auto buffer_resource = ResourcesManager::create_config_resources(cfg_index,
- parsing_info.cfg_infos_per_context[ctxt_index].at(cfg_index), driver);
+ auto buffer_resource = ConfigBuffer::create(driver, cfg_index,
+ parsing_info.cfg_infos_per_context[ctxt_index].at(cfg_index));
CHECK_EXPECTED(buffer_resource);
dynamic_cfg_vector_per_context.emplace_back(buffer_resource.release());
auto network_index_map = build_network_index_map(network_group_proto, network_group_metadata->supported_features());
CHECK_EXPECTED(network_index_map);
+
+ auto latency_meters = create_latency_meters_from_config_params(config_params, network_group_metadata);
+ CHECK_EXPECTED(latency_meters);
ResourcesManager resources_manager(vdma_device, driver, config_params,
std::move(preliminary_configs_vector), std::move(dynamic_cfg_vectors), std::move(network_group_metadata), net_group_index,
- std::move(network_index_map.release()));
+ std::move(network_index_map.release()), latency_meters.release());
auto status = resources_manager.set_number_of_cfg_channels(cfg_channels_count);
CHECK_SUCCESS_AS_EXPECTED(status);
return resources_manager;
}
-hailo_status ResourcesManager::fill_network_batch_size(CONTROL_PROTOCOL__application_header_t &app_header)
+hailo_status ResourcesManager::fill_infer_features(CONTROL_PROTOCOL__application_header_t &app_header)
+{
+ app_header.infer_features.preliminary_run_asap = m_network_group_metadata->supported_features().preliminary_run_asap;
+ return HAILO_SUCCESS;
+}
+
+hailo_status ResourcesManager::fill_network_batch_size(CONTROL_PROTOCOL__application_header_t &app_header, bool is_scheduler_used)
{
app_header.networks_count = static_cast<uint8_t>(m_config_params.network_params_by_name.size());
for (const auto &network_pair : m_config_params.network_params_by_name) {
- auto network_name = network_pair.first;
+ auto network_name_from_params = network_pair.first;
uint8_t network_index = 0;
for (network_index = 0; network_index < m_network_index_map.size(); network_index++) {
- auto const partial_network_name = m_network_index_map[network_index];
- auto found = network_name.find(HAILO_DEFAULT_NETWORK_NAME_QUALIFIER + partial_network_name);
- if (found != std::string::npos) {
- app_header.batch_size[network_index] = network_pair.second.batch_size;
+ auto const network_name_from_map = m_network_index_map[network_index];
+ if (network_name_from_map == network_name_from_params) {
+ app_header.batch_size[network_index] = (is_scheduler_used) ? HAILO_DEFAULT_BATCH_SIZE : network_pair.second.batch_size;
break;
}
}
if (m_network_index_map.size() == network_index) {
- LOGGER__ERROR("Failed to find network with network name {}", network_name);
+ LOGGER__ERROR("Failed to find network with network name {}", network_name_from_params);
return HAILO_NOT_FOUND;
}
}
return HAILO_SUCCESS;
}
-hailo_status ResourcesManager::create_vdma_channels()
+hailo_status ResourcesManager::create_internal_vdma_channels()
{
std::vector<uint8_t> intermediate_channels_idx;
std::vector<uint8_t> cfg_channels_idx;
return HAILO_SUCCESS;
}
+Expected<std::shared_ptr<VdmaChannel>> ResourcesManager::create_boundary_vdma_channel(
+ uint8_t channel_index, uint32_t transfer_size, const std::string &network_name, const std::string &stream_name,
+ VdmaChannel::Direction channel_direction)
+{
+ auto network_batch_size = get_network_batch_size(network_name);
+ CHECK_EXPECTED(network_batch_size);
+ uint32_t min_active_trans = MIN_ACTIVE_TRANSFERS_SCALE * network_batch_size.value();
+ uint32_t max_active_trans = MAX_ACTIVE_TRANSFERS_SCALE * network_batch_size.value();
+
+ CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(min_active_trans), HAILO_INVALID_ARGUMENT,
+ "calculated min_active_trans for vdma descriptor list is out of UINT16 range");
+
+ CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(max_active_trans), HAILO_INVALID_ARGUMENT,
+ "calculated min_active_trans for vdma descriptor list is out of UINT16 range");
+
+ auto edge_layer = m_network_group_metadata->get_layer_info_by_stream_name(stream_name);
+ CHECK_EXPECTED(edge_layer);
+ auto latency_meter = (contains(m_latency_meters, edge_layer->network_name)) ? m_latency_meters.at(edge_layer->network_name) : nullptr;
+ auto stream_index = edge_layer.value().index;
+
+ /* TODO - HRT-6829- page_size should be calculated inside the vDMA channel class create function */
+ auto desc_sizes_pair = VdmaDescriptorList::get_desc_buffer_sizes_for_single_transfer(m_driver,
+ static_cast<uint16_t>(min_active_trans), static_cast<uint16_t>(max_active_trans), transfer_size);
+ CHECK_EXPECTED(desc_sizes_pair);
+
+ const auto page_size = desc_sizes_pair->first;
+ const auto descs_count = desc_sizes_pair->second;
+ auto channel = VdmaChannel::create(channel_index, channel_direction, m_driver, page_size,
+ stream_index, latency_meter, network_batch_size.value());
+ CHECK_EXPECTED(channel);
+ const auto status = channel->allocate_resources(descs_count);
+ CHECK_SUCCESS_AS_EXPECTED(status);
+
+ auto channel_ptr = make_shared_nothrow<VdmaChannel>(channel.release());
+ CHECK_NOT_NULL_AS_EXPECTED(channel_ptr, HAILO_OUT_OF_HOST_MEMORY);
+
+ m_boundary_channels.emplace(stream_name, channel_ptr);
+
+ return channel_ptr;
+}
+
+Expected<std::shared_ptr<VdmaChannel>> ResourcesManager::get_boundary_vdma_channel_by_stream_name(const std::string &stream_name)
+{
+ auto boundary_channel_it = m_boundary_channels.find(stream_name);
+ if (std::end(m_boundary_channels) == boundary_channel_it) {
+ return make_unexpected(HAILO_NOT_FOUND);
+ }
+
+ return std::shared_ptr<VdmaChannel>(m_boundary_channels[stream_name]);
+}
+
ExpectedRef<IntermediateBuffer> ResourcesManager::create_inter_context_buffer(uint32_t transfer_size,
- uint8_t src_stream_index, uint8_t src_context_index, const std::string &partial_network_name)
+ uint8_t src_stream_index, uint8_t src_context_index, const std::string &network_name)
{
- auto network_batch_size_exp = get_network_batch_size_from_partial_name(partial_network_name);
+ auto network_batch_size_exp = get_network_batch_size(network_name);
CHECK_EXPECTED(network_batch_size_exp);
auto network_batch_size = network_batch_size_exp.value();
const auto intermediate_buffer_key = std::make_pair(src_context_index, src_stream_index);
- auto intermediate_buffer = create_intermediate_buffer(transfer_size, network_batch_size, intermediate_buffer_key);
+ auto intermediate_buffer = create_intermediate_buffer(IntermediateBuffer::ChannelType::INTER_CONTEXT, transfer_size,
+ network_batch_size, intermediate_buffer_key);
CHECK_EXPECTED(intermediate_buffer);
auto intermediate_buffer_ref = intermediate_buffer.release();
return make_unexpected(HAILO_NOT_FOUND);
}
- return std::ref(*intermediate_buffer_it->second);
-}
-
-Expected<std::pair<uint16_t, uint32_t>> ResourcesManager::get_desc_buffer_sizes_for_boundary_channel(
- uint32_t transfer_size, const std::string &partial_network_name)
-{
- auto network_batch_size = get_network_batch_size_from_partial_name(partial_network_name);
- CHECK_EXPECTED(network_batch_size);
- uint32_t min_active_trans = MIN_ACTIVE_TRANSFERS_SCALE * network_batch_size.value();
- uint32_t max_active_trans = MAX_ACTIVE_TRANSFERS_SCALE * network_batch_size.value();
-
- CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(min_active_trans), HAILO_INVALID_ARGUMENT,
- "calculated min_active_trans for vdma descriptor list is out of UINT16 range");
-
- CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(max_active_trans), HAILO_INVALID_ARGUMENT,
- "calculated min_active_trans for vdma descriptor list is out of UINT16 range");
-
- return VdmaDescriptorList::get_desc_buffer_sizes_for_single_transfer(m_driver,
- static_cast<uint16_t>(min_active_trans), static_cast<uint16_t>(max_active_trans), transfer_size);
+ return std::ref(intermediate_buffer_it->second);
}
-Expected<CONTROL_PROTOCOL__application_header_t> ResourcesManager::get_control_network_group_header()
+Expected<CONTROL_PROTOCOL__application_header_t> ResourcesManager::get_control_network_group_header(bool is_scheduler_used)
{
CONTROL_PROTOCOL__application_header_t app_header = {};
app_header.dynamic_contexts_count = static_cast<uint8_t>(m_contexts.size() - 1);
app_header.host_boundary_channels_bitmap = 0;
- app_header.host_ddr_channels_bitmap = 0;
/* Bitmask of all boundary and DDR channels*/
int host_boundary_channels_bitmap_local = 0;
- int host_ddr_channels_bitmap_local = 0;
for (size_t i = MIN_H2D_CHANNEL_INDEX; i <= MAX_D2H_CHANNEL_INDEX; i++) {
/* Set boundary channels */
if (m_channels_info[i].is_type(ChannelInfo::Type::BOUNDARY) && m_channels_info[i].is_used()) {
host_boundary_channels_bitmap_local |= 1 << i;
}
- /* DDR buffer channels are host controlled only if the HEF does not support padded ddr buffers */
- else if ((m_channels_info[i].is_type(ChannelInfo::Type::DDR) && (!get_supported_features().padded_ddr_buffers)) &&
- (m_channels_info[i].is_used())) {
- host_ddr_channels_bitmap_local |= 1 << i;
- }
}
app_header.host_boundary_channels_bitmap = static_cast<uint32_t>(host_boundary_channels_bitmap_local);
- app_header.host_ddr_channels_bitmap = static_cast<uint32_t>(host_ddr_channels_bitmap_local);
uint8_t cfg_handle_idx = 0;
for (uint8_t ch_idx = MIN_H2D_CHANNEL_INDEX; ch_idx <= MAX_H2D_CHANNEL_INDEX; ch_idx++) {
cfg_handle_idx++;
}
}
- app_header.cfg_channels_count = cfg_handle_idx;
app_header.power_mode = static_cast<uint8_t>(m_config_params.power_mode);
- fill_network_batch_size(app_header);
+ CHECK_SUCCESS_AS_EXPECTED(fill_infer_features(app_header), "Invalid infer features");
+ CHECK_SUCCESS_AS_EXPECTED(fill_network_batch_size(app_header, is_scheduler_used), "Invalid network batch sizes");
return app_header;
}
continue;
}
+ // In preliminary_run_asap, channels are reused across contexts (same channels in the preliminary
+ // context and first dynamic context).
+ if (get_supported_features().preliminary_run_asap) {
+ if (m_channels_info[index].is_used() &&
+ (m_channels_info[index].get_layer_name() == layer_name) &&
+ (m_channels_info[index].is_type(required_type))) {
+ LOGGER__TRACE("Reusing channel {} for layer {} (running in preliminary_run_asap mode)",
+ index, layer_name);
+ return index;
+ }
+ }
+
// Use the empty channel if available
if (!m_channels_info[index].is_used()) {
m_channels_info[index].set_type(required_type);
return index;
}
- // If DDR is managed by the FW - allow reuse of channels for DDR / inter_context
- if (get_supported_features().padded_ddr_buffers) {
- if (((ChannelInfo::Type::BOUNDARY != required_type) && (ChannelInfo::Type::CFG != required_type)) &&
- ((m_channels_info[index].is_type(ChannelInfo::Type::DDR)) || (m_channels_info[index].is_type(ChannelInfo::Type::INTER_CONTEXT)))) {
- m_channels_info[index].set_type(required_type);
- m_channels_info[index].set_layer_name(layer_name);
- return index;
- }
- } else {
- // If not - allow reuse of channels for within the same type
- if (m_channels_info[index].is_type(required_type)) {
- m_channels_info[index].set_type(required_type);
- m_channels_info[index].set_layer_name(layer_name);
- return index;
- }
+ if (((ChannelInfo::Type::BOUNDARY != required_type) && (ChannelInfo::Type::CFG != required_type)) &&
+ ((m_channels_info[index].is_type(ChannelInfo::Type::DDR)) || (m_channels_info[index].is_type(ChannelInfo::Type::INTER_CONTEXT)))) {
+ m_channels_info[index].set_type(required_type);
+ m_channels_info[index].set_layer_name(layer_name);
+ return index;
}
}
void ResourcesManager::update_preliminary_config_buffer_info()
{
// Preliminary_config is the first 'context' m_contexts vector
- assert(CONTROL_PROTOCOL__MAX_CFG_CHANNELS >= m_preliminary_config.size());
- auto i = 0;
- for (const auto &config : m_preliminary_config) {
- m_contexts[0].context_cfg_base_address[i] = config.m_descriptor.dma_address();
- m_contexts[0].context_total_descriptors[i] = config.m_acc_desc_count;
- i++;
- }
+ update_config_buffer_info(m_preliminary_config, m_contexts[0]);
}
void ResourcesManager::update_dynamic_contexts_buffer_info()
// Preliminary_config is the first 'context' m_contexts vector
assert((m_dynamic_config.size() + 1) == m_contexts.size());
int ctxt_index = 1;
- for (const auto &cfg_context : m_dynamic_config) {
- assert(CONTROL_PROTOCOL__MAX_CFG_CHANNELS >= cfg_context.size());
- auto i = 0;
- for (auto &cfg : cfg_context) {
- m_contexts[ctxt_index].context_cfg_base_address[i] = cfg.m_descriptor.dma_address();
- m_contexts[ctxt_index].context_total_descriptors[i] = cfg.m_acc_desc_count;
- i++;
- }
+ for (auto &cfg_context : m_dynamic_config) {
+ update_config_buffer_info(cfg_context, m_contexts[ctxt_index]);
ctxt_index++;
}
}
const uint32_t transfer_size = ddr_info.row_size * DDR_NUMBER_OF_ROWS_PER_INTERRUPT;
auto intermediate_buffer_key = std::make_pair(context_index, ddr_info.d2h_stream_index);
- return create_intermediate_buffer(transfer_size, static_cast<uint16_t>(number_of_transfers),
+ return create_intermediate_buffer(IntermediateBuffer::ChannelType::DDR, transfer_size, static_cast<uint16_t>(number_of_transfers),
intermediate_buffer_key);
}
CHECK_SUCCESS(status);
}
- /* If ddr supported padded buffers - DDR buffers are managed by the FW */
- if (get_supported_features().padded_ddr_buffers) {
- for (auto &ch : m_ddr_buffer_channels) {
- status = ch.register_fw_controlled_channel();
- CHECK_SUCCESS(status);
- }
+ for (auto &ch : m_ddr_buffer_channels) {
+ status = ch.register_fw_controlled_channel();
+ CHECK_SUCCESS(status);
}
return HAILO_SUCCESS;
CHECK_SUCCESS(status);
}
- /* If ddr supported padded buffers - DDR buffers are managed by the FW */
- if (get_supported_features().padded_ddr_buffers) {
- for (auto &ch : m_ddr_buffer_channels) {
- status = ch.unregister_fw_controlled_channel();
- CHECK_SUCCESS(status);
- }
+ for (auto &ch : m_ddr_buffer_channels) {
+ status = ch.unregister_fw_controlled_channel();
+ CHECK_SUCCESS(status);
+ }
+
+ return HAILO_SUCCESS;
+}
+
+hailo_status ResourcesManager::set_inter_context_channels_dynamic_batch_size(uint16_t dynamic_batch_size)
+{
+ for (auto &key_buff_pair : m_intermediate_buffers) {
+ const auto status = key_buff_pair.second.reprogram_inter_context(dynamic_batch_size);
+ CHECK_SUCCESS(status);
}
return HAILO_SUCCESS;
}
-Expected<uint16_t> ResourcesManager::get_network_batch_size_from_partial_name(const std::string &partial_network_name) const
+Expected<uint16_t> ResourcesManager::get_network_batch_size(const std::string &network_name) const
{
for (auto const &network_map: m_config_params.network_params_by_name) {
- auto const network_name = network_map.first;
- auto found = network_name.find(HAILO_DEFAULT_NETWORK_NAME_QUALIFIER + partial_network_name);
- if (found != std::string::npos) {
+ auto const network_name_from_params = network_map.first;
+ if (network_name_from_params == network_name) {
return Expected<uint16_t>(network_map.second.batch_size);
}
}
- LOGGER__ERROR("Failed to find network with network name {}", partial_network_name);
+ LOGGER__ERROR("Failed to find network with network name {}", network_name);
return make_unexpected(HAILO_NOT_FOUND);
}
return make_unexpected(HAILO_NOT_FOUND);
}
- auto &intermediate_buffer = *intermediate_buffer_it->second;
+ auto &intermediate_buffer = intermediate_buffer_it->second;
return intermediate_buffer.read();
}
-hailo_status ResourcesManager::enable_state_machine()
+hailo_status ResourcesManager::enable_state_machine(uint16_t dynamic_batch_size)
{
if (Device::Type::CORE == m_vdma_device.get_type()) {
// On core device, the nn_manager is not responsible to reset the nn-core so
CHECK_SUCCESS(status);
}
- return Control::enable_network_group(m_vdma_device, m_net_group_index);
+ return Control::enable_network_group(m_vdma_device, m_net_group_index, dynamic_batch_size);
}
hailo_status ResourcesManager::reset_state_machine()
return Control::reset_context_switch_state_machine(m_vdma_device);
}
-hailo_status ResourcesManager::open_ddr_channels()
+ExpectedRef<IntermediateBuffer> ResourcesManager::create_intermediate_buffer(
+ IntermediateBuffer::ChannelType channel_type, uint32_t transfer_size, uint16_t batch_size,
+ const IntermediateBufferKey &key)
{
- for (auto& ddr_info : m_ddr_infos) {
- for (auto &ch : m_ddr_buffer_channels) {
- if (ddr_info.d2h_channel_index == ch.channel_index) {
- auto status = ch.start_channel(*ddr_info.intermediate_buffer->get_desc_list());
- CHECK_SUCCESS(status);
- ddr_info.d2h_ch = &ch;
- }
- if (ddr_info.h2d_channel_index == ch.channel_index) {
- auto status = ch.start_channel(*ddr_info.intermediate_buffer->get_desc_list());
- CHECK_SUCCESS(status);
- ddr_info.h2d_ch = &ch;
- }
- }
- }
- return HAILO_SUCCESS;
-}
+ auto intermediate_buffer = IntermediateBuffer::create(m_driver, channel_type, transfer_size, batch_size);
+ CHECK_EXPECTED(intermediate_buffer);
-void ResourcesManager::abort_ddr_channels() // Best effort func
-{
- for (auto &ch : m_ddr_buffer_channels) {
- auto status = ch.abort();
- if (HAILO_SUCCESS != status) {
- LOGGER__ERROR("Failed to abort DDR channel {}", ch.channel_index);
- }
- }
+ auto emplace_res = m_intermediate_buffers.emplace(key, intermediate_buffer.release());
+ return std::ref(emplace_res.first->second);
}
-void ResourcesManager::close_ddr_channels() // Best effort func
+void ResourcesManager::update_config_buffer_info(std::vector<ConfigBuffer> &config_buffers,
+ CONTROL_PROTOCOL__context_switch_context_info_t &context)
{
- m_ddr_buffer_channels.clear();
-}
+ assert(CONTROL_PROTOCOL__MAX_CFG_CHANNELS >= config_buffers.size());
+ context.cfg_channels_count = static_cast<uint8_t>(config_buffers.size());
-ExpectedRef<IntermediateBuffer> ResourcesManager::create_intermediate_buffer(uint32_t transfer_size, uint16_t batch_size,
- const IntermediateBufferKey &key)
-{
- auto intermediate_buffer = IntermediateBuffer::create(IntermediateBuffer::Type::EXTERNAL_DESC, m_driver, transfer_size,
- batch_size);
- CHECK_EXPECTED(intermediate_buffer);
+ auto i = 0;
+ for (const auto &config : config_buffers) {
+ context.config_buffer_infos[i].buffer_type = static_cast<uint8_t>(
+ (config.buffer_type() == vdma::VdmaBuffer::Type::SCATTER_GATHER) ?
+ CONTROL_PROTOCOL__HOST_BUFFER_TYPE_EXTERNAL_DESC : CONTROL_PROTOCOL__HOST_BUFFER_TYPE_CCB);
+ context.config_buffer_infos[i].dma_address = config.dma_address();
+ context.config_buffer_infos[i].desc_page_size = config.desc_page_size();
+ context.config_buffer_infos[i].total_desc_count = config.total_desc_count();
+ context.config_buffer_infos[i].bytes_in_pattern = config.acc_desc_count() * config.desc_page_size();
- auto emplace_res = m_intermediate_buffers.emplace(key, intermediate_buffer.release());
- return std::ref(*emplace_res.first->second);
+ i++;
+ }
}
} /* namespace hailort */
{
public:
static Expected<HcpConfigActivatedNetworkGroup> create(Device &device, std::vector<WriteMemoryInfo> &config,
+ const std::string &network_group_name,
const hailo_activate_network_group_params_t &network_group_params,
std::map<std::string, std::unique_ptr<InputStream>> &input_streams,
std::map<std::string, std::unique_ptr<OutputStream>> &output_streams,
HcpConfigActivatedNetworkGroup(HcpConfigActivatedNetworkGroup &&other) noexcept :
ActivatedNetworkGroupBase(std::move(other)), m_active_net_group_holder(other.m_active_net_group_holder),
m_is_active(std::exchange(other.m_is_active, false)), m_power_mode(other.m_power_mode),
- m_device(other.m_device) {};
+ m_device(other.m_device), m_network_group_name(std::move(other.m_network_group_name)) {};
+
+ virtual const std::string &get_network_group_name() const override;
virtual Expected<Buffer> get_intermediate_buffer(const IntermediateBufferKey &/*key*/) override
{
private:
HcpConfigActivatedNetworkGroup(Device &device, HcpConfigActiveAppHolder &active_net_group_holder,
+ const std::string &network_group_name,
const hailo_activate_network_group_params_t &network_group_params,
std::map<std::string, std::unique_ptr<InputStream>> &input_streams,
std::map<std::string, std::unique_ptr<OutputStream>> &output_streams,
bool m_is_active;
hailo_power_mode_t m_power_mode;
Device &m_device;
+ std::string m_network_group_name;
};
} /* namespace hailort */
#define HAILO_HCP_CONFIG_MANAGER_HPP_
#include "context_switch/config_manager.hpp"
+#include "context_switch/network_group_wrapper.hpp"
#include "context_switch/single_context/hcp_config_network_group.hpp"
#include "hailo/hailort.h"
#include "hailo/device.hpp"
virtual ConfigManagerType get_manager_type();
virtual Expected<ConfiguredNetworkGroupVector> add_hef(Hef &hef,
- const NetworkGroupsParamsMap &configure_params={});
+ const NetworkGroupsParamsMap &configure_params, bool is_scheduler_used = false);
HcpConfigManager(const HcpConfigManager &other) = delete;
HcpConfigManager &operator=(const HcpConfigManager &other) = delete;
private:
// TODO: (SDK-16665) Dont need is_active flag for dtor?
std::vector<std::shared_ptr<HcpConfigNetworkGroup>> m_net_groups;
+ std::vector<std::shared_ptr<ConfiguredNetworkGroupWrapper>> m_net_group_wrappers;
Device &m_device;
HcpConfigActiveAppHolder m_active_net_group_holder;
};
const ConfigureNetworkParams &config_params, uint8_t net_group_index,
NetworkGroupMetadata &&network_group_metadata, hailo_status &status);
- virtual Expected<std::unique_ptr<ActivatedNetworkGroup>> activate(
- const hailo_activate_network_group_params_t &network_group_params = HailoRTDefaults::get_network_group_params()) override;
+ virtual Expected<std::unique_ptr<ActivatedNetworkGroup>> activate_impl(
+ const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) override;
virtual Expected<hailo_stream_interface_t> get_default_streams_interface() override;
virtual Expected<uint8_t> get_boundary_channel_index(uint8_t stream_index, hailo_stream_direction_t direction,
const std::string &layer_name) override;
+ virtual Expected<std::shared_ptr<LatencyMetersMap>> get_latnecy_meters() override;
+ virtual Expected<std::shared_ptr<VdmaChannel>> get_boundary_vdma_channel_by_stream_name(
+ const std::string &stream_name) override;
+ virtual hailo_status set_scheduler_timeout(const std::chrono::milliseconds &timeout, const std::string &network_name) override;
+ virtual hailo_status set_scheduler_threshold(uint32_t threshold, const std::string &network_name) override;
virtual ~HcpConfigNetworkGroup() = default;
HcpConfigNetworkGroup(const HcpConfigNetworkGroup &other) = delete;
Expected<VdmaConfigActivatedNetworkGroup> VdmaConfigActivatedNetworkGroup::create(
VdmaConfigActiveAppHolder &active_net_group_holder,
+ const std::string &network_group_name,
std::vector<std::shared_ptr<ResourcesManager>> resources_managers,
const hailo_activate_network_group_params_t &network_group_params,
+ uint16_t dynamic_batch_size,
std::map<std::string, std::unique_ptr<InputStream>> &input_streams,
std::map<std::string, std::unique_ptr<OutputStream>> &output_streams,
EventPtr network_group_activated_event,
CHECK_ARG_NOT_NULL_AS_EXPECTED(deactivation_time_accumulator);
auto status = HAILO_UNINITIALIZED;
- VdmaConfigActivatedNetworkGroup object(network_group_params, input_streams, output_streams,
+ VdmaConfigActivatedNetworkGroup object(network_group_name, network_group_params, dynamic_batch_size, input_streams, output_streams,
std::move(resources_managers), active_net_group_holder, std::move(network_group_activated_event),
deactivation_time_accumulator, status);
CHECK_SUCCESS_AS_EXPECTED(status);
}
VdmaConfigActivatedNetworkGroup::VdmaConfigActivatedNetworkGroup(
- const hailo_activate_network_group_params_t &network_group_params,
- std::map<std::string, std::unique_ptr<InputStream>> &input_streams,
- std::map<std::string, std::unique_ptr<OutputStream>> &output_streams,
- std::vector<std::shared_ptr<ResourcesManager>> &&resources_managers,
- VdmaConfigActiveAppHolder &active_net_group_holder,
- EventPtr &&network_group_activated_event,
- AccumulatorPtr deactivation_time_accumulator,
- hailo_status &status) :
- ActivatedNetworkGroupBase(network_group_params, input_streams, output_streams,
- std::move(network_group_activated_event), status),
- m_should_reset_state_machine(true),
- m_active_net_group_holder(active_net_group_holder),
- m_resources_managers(std::move(resources_managers)),
- m_ddr_send_threads(),
- m_ddr_recv_threads(),
- m_deactivation_time_accumulator(deactivation_time_accumulator)
+ const std::string &network_group_name,
+ const hailo_activate_network_group_params_t &network_group_params,
+ uint16_t dynamic_batch_size,
+ std::map<std::string, std::unique_ptr<InputStream>> &input_streams,
+ std::map<std::string, std::unique_ptr<OutputStream>> &output_streams,
+ std::vector<std::shared_ptr<ResourcesManager>> &&resources_managers,
+ VdmaConfigActiveAppHolder &active_net_group_holder,
+ EventPtr &&network_group_activated_event,
+ AccumulatorPtr deactivation_time_accumulator,
+ hailo_status &status) :
+ ActivatedNetworkGroupBase(network_group_params, dynamic_batch_size, input_streams,
+ output_streams, std::move(network_group_activated_event), status),
+ m_network_group_name(network_group_name),
+ m_should_reset_state_machine(true),
+ m_active_net_group_holder(active_net_group_holder),
+ m_resources_managers(std::move(resources_managers)),
+ m_ddr_send_threads(),
+ m_ddr_recv_threads(),
+ m_deactivation_time_accumulator(deactivation_time_accumulator)
{
// Validate ActivatedNetworkGroup status
if (HAILO_SUCCESS != status) {
LOGGER__ERROR("Failed to start fw managed vdma channels.");
return;
}
- }
- /* If ddr buffers are not SDK padded, host should control the DDR buffering */
- if (!m_resources_managers[0]->get_supported_features().padded_ddr_buffers) { // All ResourceManagers shares the same supported_features
- status = init_ddr_resources();
+ status = resources_manager->set_inter_context_channels_dynamic_batch_size(dynamic_batch_size);
if (HAILO_SUCCESS != status) {
- LOGGER__ERROR("Failed to initialize DDR resources.");
+ LOGGER__ERROR("Failed to set inter-context channels dynamic batch size.");
return;
}
}
for (auto &resources_manager : m_resources_managers) {
- status = resources_manager->enable_state_machine();
+ status = resources_manager->enable_state_machine(dynamic_batch_size);
if (HAILO_SUCCESS != status) {
LOGGER__ERROR("Failed to activate state-machine");
return;
VdmaConfigActivatedNetworkGroup::VdmaConfigActivatedNetworkGroup(VdmaConfigActivatedNetworkGroup &&other) noexcept :
ActivatedNetworkGroupBase(std::move(other)),
+ m_network_group_name(std::move(other.m_network_group_name)),
m_should_reset_state_machine(std::exchange(other.m_should_reset_state_machine, false)),
m_active_net_group_holder(other.m_active_net_group_holder),
m_resources_managers(std::move(other.m_resources_managers)),
auto status = HAILO_UNINITIALIZED;
const auto start_time = std::chrono::steady_clock::now();
- // If ddr buffers are not SDK padded, host should control the DDR buffering
- // Note: All ResourceManagers share the same supported_features
- if (!m_resources_managers[0]->get_supported_features().padded_ddr_buffers) {
- status = cleanup_ddr_resources();
- if (HAILO_SUCCESS != status) {
- LOGGER__ERROR("Failed to cleanup DDR resources.");
- }
- }
-
m_active_net_group_holder.clear();
deactivate_resources();
m_deactivation_time_accumulator->add_data_point(elapsed_time_ms);
}
+const std::string &VdmaConfigActivatedNetworkGroup::get_network_group_name() const
+{
+ return m_network_group_name;
+}
+
Expected<Buffer> VdmaConfigActivatedNetworkGroup::get_intermediate_buffer(const IntermediateBufferKey &key)
{
CHECK_AS_EXPECTED(1 == m_resources_managers.size(), HAILO_INVALID_OPERATION,
return m_resources_managers[0]->read_intermediate_buffer(key);
}
-hailo_status VdmaConfigActivatedNetworkGroup::init_ddr_resources()
-{
- for (auto &resources_manager : m_resources_managers) {
- auto status = resources_manager->open_ddr_channels();
- CHECK_SUCCESS(status);
-
- for (auto &ddr_info : resources_manager->ddr_infos()) {
- auto num_ready = make_shared_nothrow<std::atomic<uint16_t>>(static_cast<uint16_t>(0));
- CHECK_NOT_NULL(num_ready, HAILO_OUT_OF_HOST_MEMORY);
-
- m_ddr_send_threads.push_back(std::thread(ddr_send_thread_main, ddr_info, num_ready));
- m_ddr_recv_threads.push_back(std::thread(ddr_recv_thread_main, ddr_info, num_ready));
- }
- }
- return HAILO_SUCCESS;
-}
-
-hailo_status VdmaConfigActivatedNetworkGroup::cleanup_ddr_resources()
-{
- hailo_status status = HAILO_SUCCESS; // Success oriented
-
- for (auto &resources_manager : m_resources_managers) {
- resources_manager->abort_ddr_channels();
- }
-
- for (auto& thread : m_ddr_send_threads) {
- thread.join();
- }
- m_ddr_send_threads.clear();
-
- for (auto& thread : m_ddr_recv_threads) {
- thread.join();
- }
- m_ddr_recv_threads.clear();
-
- for (auto &resources_manager : m_resources_managers) {
- resources_manager->close_ddr_channels();
- }
-
- return status;
-}
-
-void VdmaConfigActivatedNetworkGroup::ddr_send_thread_main(DdrChannelsInfo ddr_info,
- std::shared_ptr<std::atomic<uint16_t>> desc_list_num_ready)
-{
- hailo_status status = HAILO_UNINITIALIZED;
- const auto timeout = std::chrono::milliseconds(DDR_THREAD_DEFAULT_TIMEOUT_MS);
- uint16_t last_num_proc = 0;
- uint32_t acc_sent_descs = 0;
- auto descs_per_interrupt = ddr_info.intermediate_buffer->descriptors_in_frame();
- assert(0 == (ddr_info.min_buffered_rows % DDR_NUMBER_OF_ROWS_PER_INTERRUPT));
- auto interrupts_per_min_buffered_rows = ddr_info.min_buffered_rows / DDR_NUMBER_OF_ROWS_PER_INTERRUPT;
- uint32_t descs_per_min_buffered_rows = interrupts_per_min_buffered_rows * descs_per_interrupt;
-
- if (nullptr == ddr_info.h2d_ch) {
- LOGGER__ERROR("Failed to find DDR H2D channel {}.", ddr_info.h2d_channel_index);
- return;
- }
- if (nullptr == ddr_info.d2h_ch) {
- LOGGER__ERROR("Failed to find DDR D2H channel {}.", ddr_info.d2h_channel_index);
- return;
- }
-
- while (true) {
- /* H2D */
- status = ddr_info.h2d_ch->wait_channel_interrupts_for_ddr(timeout);
- if (HAILO_SUCCESS != status) {
- goto l_exit;
- }
-
- /* D2H */
- auto hw_num_proc = ddr_info.h2d_ch->get_hw_num_processed_ddr(ddr_info.desc_list_size_mask);
- if (!hw_num_proc) {
- LOGGER__ERROR("Failed to get DDR_H2D_Channel {} num_processed.", ddr_info.h2d_channel_index);
- status = hw_num_proc.status();
- goto l_exit;
- }
-
- auto transferred_descs = (last_num_proc <= hw_num_proc.value()) ?
- static_cast<uint16_t>(hw_num_proc.value() - last_num_proc) :
- static_cast<uint16_t>(ddr_info.intermediate_buffer->descs_count() - last_num_proc + hw_num_proc.value());
- acc_sent_descs += transferred_descs;
- last_num_proc = hw_num_proc.value();
-
- auto sent_batches = acc_sent_descs / descs_per_min_buffered_rows;
- if (0 < sent_batches) {
- auto desc_count = ddr_info.intermediate_buffer->program_host_managed_ddr(ddr_info.row_size,
- (ddr_info.min_buffered_rows * sent_batches), *desc_list_num_ready);
- if (!desc_count) {
- LOGGER__ERROR("Failed to program descs for DDR");
- status = desc_count.status();
- goto l_exit;
- }
- acc_sent_descs -= desc_count.value();
- *desc_list_num_ready =
- static_cast<uint16_t>((desc_count.value() + *desc_list_num_ready) & ddr_info.desc_list_size_mask);
-
- status = ddr_info.d2h_ch->inc_num_available_for_ddr(desc_count.value(),
- ddr_info.desc_list_size_mask);
- if (HAILO_SUCCESS != status) {
- goto l_exit;
- }
- }
- }
-l_exit:
- if (HAILO_SUCCESS != status) {
- if ((HAILO_STREAM_INTERNAL_ABORT == status) || (HAILO_STREAM_NOT_ACTIVATED == status)) {
- LOGGER__INFO("DDR thread main for channels {}:(h2d), {}:(d2h) exit with status {}",ddr_info.h2d_channel_index,
- ddr_info.d2h_channel_index, status);
- } else {
- LOGGER__ERROR("DDR thread main for channels {}:(h2d), {}:(d2h) exit with status {}",ddr_info.h2d_channel_index,
- ddr_info.d2h_channel_index, status);
- }
- }
- return;
-}
-
-void VdmaConfigActivatedNetworkGroup::ddr_recv_thread_main(DdrChannelsInfo ddr_info,
- std::shared_ptr<std::atomic<uint16_t>> desc_list_num_ready)
-{
- hailo_status status = HAILO_UNINITIALIZED;
- uint16_t last_num_proc = 0;
- uint16_t transferred_descs = 0;
- const auto timeout = std::chrono::milliseconds(DDR_THREAD_DEFAULT_TIMEOUT_MS);
-
- if (nullptr == ddr_info.h2d_ch) {
- LOGGER__ERROR("Failed to find DDR H2D channel {}.", ddr_info.h2d_channel_index);
- return;
- }
- if (nullptr == ddr_info.d2h_ch) {
- LOGGER__ERROR("Failed to find DDR D2H channel {}.", ddr_info.d2h_channel_index);
- return;
- }
-
- *desc_list_num_ready = ddr_info.initial_programed_descs;
-
- status = ddr_info.d2h_ch->set_num_avail_value(ddr_info.initial_programed_descs);
- if (HAILO_SUCCESS != status) {
- goto l_exit;
- }
-
- while (true) {
- /* D2H */
- status = ddr_info.d2h_ch->wait_channel_interrupts_for_ddr(timeout);
- if (HAILO_SUCCESS != status) {
- goto l_exit;
- }
-
- /* H2D */
- auto hw_num_proc = ddr_info.d2h_ch->get_hw_num_processed_ddr(ddr_info.desc_list_size_mask);
- if (!hw_num_proc) {
- LOGGER__ERROR("Failed to get DDR_D2H_Channel {} num_processed.", ddr_info.d2h_channel_index);
- status = hw_num_proc.status();
- goto l_exit;
- }
-
- transferred_descs = (last_num_proc <= hw_num_proc.value()) ?
- static_cast<uint16_t>(hw_num_proc.value() - last_num_proc) :
- static_cast<uint16_t>(ddr_info.intermediate_buffer->descs_count() - last_num_proc + hw_num_proc.value());
- last_num_proc = hw_num_proc.value();
-
- status = ddr_info.h2d_ch->inc_num_available_for_ddr(transferred_descs,
- ddr_info.desc_list_size_mask);
- if (HAILO_SUCCESS != status) {
- goto l_exit;
- }
- }
-l_exit:
- if (HAILO_SUCCESS != status) {
- if ((HAILO_STREAM_INTERNAL_ABORT == status) || (HAILO_STREAM_NOT_ACTIVATED == status)) {
- LOGGER__INFO("DDR thread main for channels {}:(h2d), {}:(d2h) exit with status {}",ddr_info.h2d_channel_index,
- ddr_info.d2h_channel_index, status);
- } else {
- LOGGER__ERROR("DDR thread main for channels {}:(h2d), {}:(d2h) exit with status {}",ddr_info.h2d_channel_index,
- ddr_info.d2h_channel_index, status);
- }
- }
- return;
-}
-
} /* namespace hailort */
#include "hailo/hef.hpp"
#include "control.hpp"
#include "hailort_defaults.hpp"
+#include "vdevice_internal.hpp"
#include "pcie_device.hpp"
#include "hlpcie.hpp"
const bool is_vdevice = false;
std::vector<std::reference_wrapper<VdmaDevice>> devices;
devices.push_back(device);
- VdmaConfigManager manager(std::move(devices), is_vdevice);
+
+ auto empty_weak_ptr = NetworkGroupSchedulerWeakPtr();
+ VdmaConfigManager manager(std::move(devices), is_vdevice, empty_weak_ptr);
return manager;
}
pcie_devices.emplace_back(static_cast<PcieDevice&>(dev.get()));
}
-
- VdmaConfigManager manager(std::move(pcie_devices), is_vdevice);
+ VdmaConfigManager manager(std::move(pcie_devices), is_vdevice, static_cast<VDeviceBase&>(vdevice).network_group_scheduler());
return manager;
}
-VdmaConfigManager::VdmaConfigManager(std::vector<std::reference_wrapper<VdmaDevice>> &&devices, bool is_vdevice)
- : m_devices(std::move(devices)), m_net_groups(), m_is_vdevice(is_vdevice) {}
+VdmaConfigManager::VdmaConfigManager(std::vector<std::reference_wrapper<VdmaDevice>> &&devices, bool is_vdevice, NetworkGroupSchedulerWeakPtr network_group_scheduler)
+ : m_devices(std::move(devices)), m_net_groups(), m_net_group_wrappers(), m_is_vdevice(is_vdevice), m_network_group_scheduler(network_group_scheduler) {}
Expected<ConfiguredNetworkGroupVector> VdmaConfigManager::add_hef(Hef &hef,
- const NetworkGroupsParamsMap &configure_params)
+ const NetworkGroupsParamsMap &configure_params, bool scheduler_is_used)
{
auto &hef_network_groups = hef.pimpl->network_groups();
auto current_net_group_index = static_cast<uint8_t>(m_net_groups.size());
}
auto net_group = VdmaConfigNetworkGroup::create(m_active_net_group_holder, config_params,
- resources_managers, network_group_metadata_ptr);
+ resources_managers, network_group_metadata_ptr, m_network_group_scheduler);
current_net_group_index++;
auto net_group_ptr = make_shared_nothrow<VdmaConfigNetworkGroup>(net_group.release());
// TODO: move this func into VdmaConfigNetworkGroup c'tor
if (m_is_vdevice) {
- status = net_group_ptr->create_vdevice_streams_from_config_params();
+ auto network_group_handle = INVALID_NETWORK_GROUP_HANDLE;
+ auto network_group_scheduler = m_network_group_scheduler.lock();
+ if (network_group_scheduler) {
+ auto network_group_handle_exp = network_group_scheduler->add_network_group(net_group_ptr);
+ CHECK_EXPECTED(network_group_handle_exp);
+ network_group_handle = network_group_handle_exp.value();
+ net_group_ptr->set_network_group_handle(network_group_handle);
+ }
+
+ status = net_group_ptr->create_vdevice_streams_from_config_params(network_group_handle);
CHECK_SUCCESS_AS_EXPECTED(status);
} else {
status = net_group_ptr->create_streams_from_config_params(net_group_ptr->get_resources_managers()[0]->get_device());
status = validate_boundary_streams_were_created(hef, network_group_proto->network_group_metadata().network_group_name(), *net_group_ptr);
CHECK_SUCCESS_AS_EXPECTED(status);
- added_network_groups.emplace_back(std::static_pointer_cast<ConfiguredNetworkGroup>(net_group_ptr));
+ auto net_group_wrapper = ConfiguredNetworkGroupWrapper::create(net_group_ptr);
+ CHECK_EXPECTED(net_group_wrapper);
+
+ auto net_group_wrapper_ptr = make_shared_nothrow<ConfiguredNetworkGroupWrapper>(net_group_wrapper.release());
+ CHECK_AS_EXPECTED(nullptr != net_group_wrapper_ptr, HAILO_OUT_OF_HOST_MEMORY);
+ m_net_group_wrappers.emplace_back(net_group_wrapper_ptr);
+
+ added_network_groups.emplace_back(std::static_pointer_cast<ConfiguredNetworkGroup>(net_group_wrapper_ptr));
}
std::string unmatched_keys = "";
for (const auto &pair : configure_params_copy) {
for (size_t i = 0, contexts = 0; i < m_net_groups.size(); ++i) {
for (auto &resource_manager : m_net_groups[i]->get_resources_managers()) {
if (0 == strcmp(device.get().get_dev_id(), resource_manager->get_dev_id())) {
- auto net_group_header_exp = resource_manager->get_control_network_group_header();
+ auto net_group_header_exp = resource_manager->get_control_network_group_header(scheduler_is_used);
CHECK_EXPECTED(net_group_header_exp);
context_switch_info.context_switch_main_header.application_header[i] = net_group_header_exp.value();
auto net_group_contexts = resource_manager->get_contexts();
}
}
- // Reset context_switch status
- auto status = Control::reset_context_switch_state_machine(device.get());
- CHECK_SUCCESS_AS_EXPECTED(status);
+ {
+ // Add instance that guards scheduler to deactivate network_group temporary
+ auto scheduler_idle_guard = NetworkGroupScheduler::create_scheduler_idle_guard();
+ if (m_is_vdevice) {
+ auto network_group_scheduler = m_network_group_scheduler.lock();
+ if (network_group_scheduler) {
+ auto status = scheduler_idle_guard->set_scheduler(network_group_scheduler);
+ CHECK_SUCCESS_AS_EXPECTED(status);
+ }
+ }
- // Write context_switch info
- status = Control::write_context_switch_info(device.get(), &context_switch_info);
- CHECK_SUCCESS_AS_EXPECTED(status);
+ // Reset context_switch status
+ auto status = Control::reset_context_switch_state_machine(device.get());
+ CHECK_SUCCESS_AS_EXPECTED(status);
+
+ // Write context_switch info
+ status = Control::write_context_switch_info(device.get(), &context_switch_info);
+ CHECK_SUCCESS_AS_EXPECTED(status);
+ }
}
return added_network_groups;
CHECK((single_network_default_batch || multi_network_default_batch), HAILO_INVALID_OPERATION,
"User provided non batch size for network group and for network as well. User is adviced to work with network's batch size only");
- /* In case user works with network group, overide the network batch size.*/
if (!single_network_default_batch && multi_network_default_batch) {
+ /* In case user works with network group, overide the network batch size.*/
for (auto &network_params : config_params.network_params_by_name) {
network_params.second.batch_size = config_params.batch_size;
}
Expected<VdmaConfigNetworkGroup> VdmaConfigNetworkGroup::create(VdmaConfigActiveAppHolder &active_net_group_holder,
const ConfigureNetworkParams &config_params,
std::vector<std::shared_ptr<ResourcesManager>> resources_managers,
- std::shared_ptr<NetworkGroupMetadata> network_group_metadata)
+ std::shared_ptr<NetworkGroupMetadata> network_group_metadata, NetworkGroupSchedulerWeakPtr network_group_scheduler)
{
auto status = HAILO_UNINITIALIZED;
VdmaConfigNetworkGroup object(active_net_group_holder, config_params,
- std::move(resources_managers), *network_group_metadata, status);
+ std::move(resources_managers), *network_group_metadata, network_group_scheduler, status);
CHECK_SUCCESS_AS_EXPECTED(status);
return object;
VdmaConfigNetworkGroup::VdmaConfigNetworkGroup(VdmaConfigActiveAppHolder &active_net_group_holder,
const ConfigureNetworkParams &config_params,
std::vector<std::shared_ptr<ResourcesManager>> &&resources_managers,
- const NetworkGroupMetadata &network_group_metadata, hailo_status &status) :
+ const NetworkGroupMetadata &network_group_metadata, NetworkGroupSchedulerWeakPtr network_group_scheduler, hailo_status &status) :
ConfiguredNetworkGroupBase(config_params,
- resources_managers[0]->get_network_group_index(),
- network_group_metadata, status), // All ResourceManagers shares the same net_group_index
+ resources_managers[0]->get_network_group_index(), // All ResourceManagers shares the same net_group_index
+ network_group_metadata, !network_group_scheduler.expired(), status),
m_active_net_group_holder(active_net_group_holder),
- m_resources_managers(std::move(resources_managers)) {}
+ m_resources_managers(std::move(resources_managers)),
+ m_network_group_scheduler(network_group_scheduler),
+ m_network_group_handle(INVALID_NETWORK_GROUP_HANDLE) {}
-Expected<std::unique_ptr<ActivatedNetworkGroup>> VdmaConfigNetworkGroup::activate(
- const hailo_activate_network_group_params_t &network_group_params)
+Expected<std::unique_ptr<ActivatedNetworkGroup>> VdmaConfigNetworkGroup::activate_impl(
+ const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size)
{
auto start_time = std::chrono::steady_clock::now();
auto activated_net_group = VdmaConfigActivatedNetworkGroup::create(
- m_active_net_group_holder, m_resources_managers, network_group_params,
+ m_active_net_group_holder, get_network_group_name(), m_resources_managers, network_group_params, dynamic_batch_size,
m_input_streams, m_output_streams, m_network_group_activated_event, m_deactivation_time_accumulator);
const auto elapsed_time_ms = std::chrono::duration<double, std::milli>(
std::chrono::steady_clock::now() - start_time).count();
return m_resources_managers[0]->get_boundary_channel_index(stream_index, direction, layer_name);
}
-hailo_status VdmaConfigNetworkGroup::create_vdevice_streams_from_config_params()
+hailo_status VdmaConfigNetworkGroup::create_vdevice_streams_from_config_params(network_group_handle_t network_group_handle)
{
- if ((m_config_params.latency & HAILO_LATENCY_MEASURE) == HAILO_LATENCY_MEASURE) {
- if (1 == m_resources_managers.size()) {
- // Best affort for starting latency meter.
- auto networks_names = m_network_group_metadata.get_partial_network_names();
- for (auto &network_name : networks_names) {
- auto layer_infos = m_network_group_metadata.get_all_layer_infos(network_name);
- CHECK_EXPECTED_AS_STATUS(layer_infos);
- auto latency_meter = ConfiguredNetworkGroupBase::create_hw_latency_meter(m_resources_managers[0]->get_device(),
- layer_infos.value());
- if (latency_meter) {
- m_latency_meter.emplace(network_name, latency_meter.release());
- LOGGER__DEBUG("Starting hw latency measurement for network {}", network_name);
- }
- }
- } else {
- LOGGER__WARNING("Latency measurement is not supported on more than 1 physical device.");
- }
+ // TODO - HRT-6931 - raise error on this case
+ if (((m_config_params.latency & HAILO_LATENCY_MEASURE) == HAILO_LATENCY_MEASURE) && (1 < m_resources_managers.size())) {
+ LOGGER__WARNING("Latency measurement is not supported on more than 1 physical device.");
}
for (const auto &stream_parameters_pair : m_config_params.stream_params_by_name) {
case HAILO_H2D_STREAM:
{
auto status = create_input_vdevice_stream_from_config_params(stream_parameters_pair.second,
- stream_parameters_pair.first);
+ stream_parameters_pair.first, network_group_handle);
CHECK_SUCCESS(status);
}
break;
case HAILO_D2H_STREAM:
{
auto status = create_output_vdevice_stream_from_config_params(stream_parameters_pair.second,
- stream_parameters_pair.first);
+ stream_parameters_pair.first, network_group_handle);
CHECK_SUCCESS(status);
}
break;
}
hailo_status VdmaConfigNetworkGroup::create_input_vdevice_stream_from_config_params(const hailo_stream_parameters_t &stream_params,
- const std::string &stream_name)
+ const std::string &stream_name, network_group_handle_t network_group_handle)
{
auto edge_layer = get_layer_info(stream_name);
CHECK_EXPECTED_AS_STATUS(edge_layer);
- auto partial_network_name = edge_layer->partial_network_name;
- auto latency_meter = (contains(m_latency_meter, partial_network_name)) ? m_latency_meter.at(partial_network_name) : nullptr;
-
CHECK(HAILO_STREAM_INTERFACE_PCIE == stream_params.stream_interface, HAILO_INVALID_OPERATION,
"Only PCIe streams are supported on VDevice usage. {} has {} interface.", stream_name, stream_params.stream_interface);
auto input_stream = VDeviceInputStream::create(m_resources_managers, edge_layer.value(),
- stream_name, m_network_group_activated_event, latency_meter);
+ stream_name, network_group_handle, m_network_group_activated_event,
+ m_network_group_scheduler);
CHECK_EXPECTED_AS_STATUS(input_stream);
m_input_streams.insert(make_pair(stream_name, input_stream.release()));
}
hailo_status VdmaConfigNetworkGroup::create_output_vdevice_stream_from_config_params(const hailo_stream_parameters_t &stream_params,
- const std::string &stream_name)
+ const std::string &stream_name, network_group_handle_t network_group_handle)
{
auto edge_layer = get_layer_info(stream_name);
CHECK_EXPECTED_AS_STATUS(edge_layer);
- auto partial_network_name = edge_layer->partial_network_name;
- auto latency_meter = (contains(m_latency_meter, partial_network_name)) ? m_latency_meter.at(partial_network_name) : nullptr;
-
CHECK(HAILO_STREAM_INTERFACE_PCIE == stream_params.stream_interface, HAILO_INVALID_OPERATION,
"Only PCIe streams are supported on VDevice usage. {} has {} interface.", stream_name, stream_params.stream_interface);
auto output_stream = VDeviceOutputStream::create(m_resources_managers, edge_layer.value(),
- stream_name, m_network_group_activated_event, latency_meter);
+ stream_name, network_group_handle, m_network_group_activated_event,
+ m_network_group_scheduler);
CHECK_EXPECTED_AS_STATUS(output_stream);
m_output_streams.insert(make_pair(stream_name, output_stream.release()));
return HAILO_SUCCESS;
}
+void VdmaConfigNetworkGroup::set_network_group_handle(network_group_handle_t handle)
+{
+ m_network_group_handle = handle;
+}
+
+hailo_status VdmaConfigNetworkGroup::set_scheduler_timeout(const std::chrono::milliseconds &timeout, const std::string &network_name)
+{
+ auto network_group_scheduler = m_network_group_scheduler.lock();
+ CHECK(network_group_scheduler, HAILO_INVALID_OPERATION,
+ "Cannot set scheduler timeout for network group {}, as it is configured on a vdevice which does not have scheduling enabled", get_network_group_name());
+ if (network_name != HailoRTDefaults::get_network_name(get_network_group_name())) {
+ CHECK(network_name.empty(), HAILO_NOT_IMPLEMENTED, "Setting scheduler timeout for a specific network is currently not supported");
+ }
+ auto status = network_group_scheduler->set_timeout(m_network_group_handle, timeout, network_name);
+ CHECK_SUCCESS(status);
+ return HAILO_SUCCESS;
+}
+
+hailo_status VdmaConfigNetworkGroup::set_scheduler_threshold(uint32_t threshold, const std::string &network_name)
+{
+ auto network_group_scheduler = m_network_group_scheduler.lock();
+ CHECK(network_group_scheduler, HAILO_INVALID_OPERATION,
+ "Cannot set scheduler threshold for network group {}, as it is configured on a vdevice which does not have scheduling enabled", get_network_group_name());
+ if (network_name != HailoRTDefaults::get_network_name(get_network_group_name())) {
+ CHECK(network_name.empty(), HAILO_NOT_IMPLEMENTED, "Setting scheduler threshold for a specific network is currently not supported");
+ }
+ auto status = network_group_scheduler->set_threshold(m_network_group_handle, threshold, network_name);
+ CHECK_SUCCESS(status);
+ return HAILO_SUCCESS;
+}
+
+Expected<std::shared_ptr<LatencyMetersMap>> VdmaConfigNetworkGroup::get_latnecy_meters()
+{
+ auto latency_meters = m_resources_managers[0]->get_latnecy_meters();
+ return make_shared_nothrow<LatencyMetersMap>(latency_meters);
+}
+
+Expected<std::shared_ptr<VdmaChannel>> VdmaConfigNetworkGroup::get_boundary_vdma_channel_by_stream_name(const std::string &stream_name)
+{
+ if (1 < m_resources_managers.size()) {
+ LOGGER__ERROR("get_boundary_vdma_channel_by_stream_name function is not supported on more than 1 physical device.");
+ return make_unexpected(HAILO_INVALID_OPERATION);
+ }
+
+ return m_resources_managers[0]->get_boundary_vdma_channel_by_stream_name(stream_name);
+}
+
} /* namespace hailort */
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#endif
+#define POWER_MEASUREMENT_DELAY_MS(__sample_period, __average_factor) \
+ (static_cast<uint32_t>((__sample_period) / 1000.0 * (__average_factor) * 2 * 1.2))
+
#define OVERCURRENT_PROTECTION_WARNING ( \
"Using the overcurrent protection dvm for power measurement will disable the ovecurrent protection.\n" \
"If only taking one measurement, the protection will resume automatically.\n" \
return status;
}
-hailo_status Control::set_power_measurement(Device &device, uint32_t index, CONTROL_PROTOCOL__dvm_options_t dvm,
+hailo_status Control::set_power_measurement(Device &device, hailo_measurement_buffer_index_t buffer_index, CONTROL_PROTOCOL__dvm_options_t dvm,
CONTROL_PROTOCOL__power_measurement_types_t measurement_type)
{
hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__payload_t *payload = NULL;
CONTROL_PROTOCOL__set_power_measurement_response_t *response = NULL;
- CHECK(CONTROL_PROTOCOL__MAX_NUMBER_OF_POWER_MEASUREMETS > index,
- HAILO_INVALID_ARGUMENT, "Invalid power measurement index {}", index);
+ CHECK(CONTROL_PROTOCOL__MAX_NUMBER_OF_POWER_MEASUREMETS > buffer_index,
+ HAILO_INVALID_ARGUMENT, "Invalid power measurement index {}", buffer_index);
common_status = CONTROL_PROTOCOL__pack_set_power_measurement_request(&request, &request_size, device.get_control_sequence(),
- index, dvm, measurement_type);
+ buffer_index, dvm, measurement_type);
status = (HAILO_COMMON_STATUS__SUCCESS == common_status) ? HAILO_SUCCESS : HAILO_INTERNAL_FAILURE;
if (HAILO_SUCCESS != status) {
goto exit;
return status;
}
-hailo_status Control::get_power_measurement(Device &device, uint32_t index, bool should_clear,
+hailo_status Control::get_power_measurement(Device &device, hailo_measurement_buffer_index_t buffer_index, bool should_clear,
hailo_power_measurement_data_t *measurement_data)
{
hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__get_power_measurement_response_t *get_power_response = NULL;
/* Validate arguments */
- CHECK(CONTROL_PROTOCOL__MAX_NUMBER_OF_POWER_MEASUREMETS > index,
- HAILO_INVALID_ARGUMENT, "Invalid power measurement index {}", index);
+ CHECK(CONTROL_PROTOCOL__MAX_NUMBER_OF_POWER_MEASUREMETS > buffer_index,
+ HAILO_INVALID_ARGUMENT, "Invalid power measurement index {}", buffer_index);
CHECK_ARG_NOT_NULL(measurement_data);
common_status = CONTROL_PROTOCOL__pack_get_power_measurement_request(&request, &request_size, device.get_control_sequence(),
- index, should_clear);
+ buffer_index, should_clear);
status = (HAILO_COMMON_STATUS__SUCCESS == common_status) ? HAILO_SUCCESS : HAILO_INTERNAL_FAILURE;
if (HAILO_SUCCESS != status) {
goto exit;
return status;
}
-hailo_status Control::start_power_measurement(Device &device, uint32_t delay_milliseconds,
+hailo_status Control::start_power_measurement(Device &device,
CONTROL_PROTOCOL__averaging_factor_t averaging_factor , CONTROL_PROTOCOL__sampling_period_t sampling_period)
{
hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__response_header_t *header = NULL;
CONTROL_PROTOCOL__payload_t *payload = NULL;
+ uint32_t delay_milliseconds = POWER_MEASUREMENT_DELAY_MS(sampling_period, averaging_factor);
+ // There is no logical way that measurement delay can be 0 - because sampling_period and averaging_factor cant be 0
+ // Hence if it is 0 - it means it was 0.xx and we want to round up to 1 in that case
+ if (0 == delay_milliseconds) {
+ delay_milliseconds = 1;
+ }
+
common_status = CONTROL_PROTOCOL__pack_start_power_measurement_request(&request, &request_size, device.get_control_sequence(),
delay_milliseconds, averaging_factor, sampling_period);
status = (HAILO_COMMON_STATUS__SUCCESS == common_status) ? HAILO_SUCCESS : HAILO_INTERNAL_FAILURE;
context_info_single_control.is_first_control_per_context = is_first_control_per_context;
context_info_single_control.is_last_control_per_context = is_last_control_per_context;
- static_assert(sizeof(context_info_single_control.context_cfg_base_address) == sizeof(context_info->context_cfg_base_address),
- "mismatch in sizes of context_cfg_base_address");
- static_assert(sizeof(context_info_single_control.context_cfg_total_descriptors) == sizeof(context_info->context_total_descriptors),
- "mismatch in sizes of context_cfg_total_descriptors");
+ static_assert(sizeof(context_info_single_control.config_buffer_infos) == sizeof(context_info->config_buffer_infos),
+ "mismatch in sizes of config_buffer_infos");
static_assert(sizeof(context_info_single_control.context_stream_remap_data) == sizeof(context_info->context_stream_remap_data),
"mismatch in sizes of context_stream_remap_data");
- memcpy(context_info_single_control.context_cfg_base_address,
- context_info->context_cfg_base_address,
- sizeof(context_info_single_control.context_cfg_base_address));
- memcpy(context_info_single_control.context_cfg_total_descriptors,
- context_info->context_total_descriptors,
- sizeof(context_info_single_control.context_cfg_total_descriptors));
+ context_info_single_control.cfg_channels_count = context_info->cfg_channels_count;
+ memcpy(context_info_single_control.config_buffer_infos,
+ context_info->config_buffer_infos,
+ sizeof(context_info_single_control.config_buffer_infos));
memcpy(&(context_info_single_control.context_stream_remap_data),
&(context_info->context_stream_remap_data),
hailo_status Control::change_context_switch_status(Device &device,
CONTROL_PROTOCOL__CONTEXT_SWITCH_STATUS_t state_machine_status,
- uint8_t network_group_index)
+ uint8_t network_group_index, uint16_t dynamic_batch_size)
{
hailo_status status = HAILO_UNINITIALIZED;
HAILO_COMMON_STATUS_t common_status = HAILO_COMMON_STATUS__UNINITIALIZED;
CONTROL_PROTOCOL__payload_t *payload = NULL;
common_status = CONTROL_PROTOCOL__pack_change_context_switch_status_request(&request, &request_size,
- device.get_control_sequence(), state_machine_status, network_group_index);
+ device.get_control_sequence(), state_machine_status, network_group_index, dynamic_batch_size);
status = (HAILO_COMMON_STATUS__SUCCESS == common_status) ? HAILO_SUCCESS : HAILO_INTERNAL_FAILURE;
if (HAILO_SUCCESS != status) {
goto exit;
return status;
}
-hailo_status Control::enable_network_group(Device &device, uint8_t network_group_index)
+hailo_status Control::enable_network_group(Device &device, uint8_t network_group_index, uint16_t dynamic_batch_size)
{
- return Control::change_context_switch_status(device, CONTROL_PROTOCOL__CONTEXT_SWITCH_STATUS_ENABLED, network_group_index);
+ return Control::change_context_switch_status(device, CONTROL_PROTOCOL__CONTEXT_SWITCH_STATUS_ENABLED,
+ network_group_index, dynamic_batch_size);
}
hailo_status Control::reset_context_switch_state_machine(Device &device)
{
- return Control::change_context_switch_status(device, CONTROL_PROTOCOL__CONTEXT_SWITCH_STATUS_RESET, 0);
+ static const auto IGNORE_NETWORK_GROUP_INDEX = 0;
+ static const auto IGNORE_DYNAMIC_BATCH_SIZE = 0;
+ return Control::change_context_switch_status(device, CONTROL_PROTOCOL__CONTEXT_SWITCH_STATUS_RESET,
+ IGNORE_NETWORK_GROUP_INDEX, IGNORE_DYNAMIC_BATCH_SIZE);
}
hailo_status Control::wd_enable(Device &device, uint8_t cpu_id, bool should_enable)
return status;
}
-hailo_status Control::switch_network_group(Device &device, uint8_t network_group_index)
+hailo_status Control::switch_network_group(Device &device, uint8_t network_group_index, uint16_t dynamic_batch_size)
{
hailo_status status = HAILO_UNINITIALIZED;
HAILO_COMMON_STATUS_t common_status = HAILO_COMMON_STATUS__UNINITIALIZED;
CONTROL_PROTOCOL__response_header_t *header = NULL;
CONTROL_PROTOCOL__payload_t *payload = NULL;
-
LOGGER__DEBUG("Set network_group_index {}", network_group_index);
common_status = CONTROL_PROTOCOL__pack_switch_application_request(&request, &request_size, device.get_control_sequence(),
- network_group_index);
+ network_group_index, dynamic_batch_size);
status = (HAILO_COMMON_STATUS__SUCCESS == common_status) ? HAILO_SUCCESS : HAILO_INTERNAL_FAILURE;
if (HAILO_SUCCESS != status) {
goto exit;
*
* @return Upon success, returns @a HAILO_SUCCESS. Otherwise, returns an @a static hailo_status error.
*/
- static hailo_status enable_network_group(Device &device,
- uint8_t network_group_index);
+ static hailo_status enable_network_group(Device &device, uint8_t network_group_index, uint16_t dynamic_batch_size);
/**
* reset context switch state machine
*
*
* @param[in] device - The Hailo device.
* @param[in] network_group_index - network_group index
+ * @param[in] dynamic_batch_size - dynamic_batch size (or CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE if it's
+ * to be ignored)
*
* @return Upon success, returns @a HAILO_SUCCESS. Otherwise, returns an @a static hailo_status error.
*/
- static hailo_status switch_network_group(Device &device, uint8_t network_group_index);
+ static hailo_status switch_network_group(Device &device, uint8_t network_group_index, uint16_t dynamic_batch_size);
/**
* Enable/disable halt transmition following Rx pause frame
// TODO: needed?
static hailo_status power_measurement(Device &device, CONTROL_PROTOCOL__dvm_options_t dvm,
CONTROL_PROTOCOL__power_measurement_types_t measurement_type, float32_t *measurement);
- static hailo_status set_power_measurement(Device &device, uint32_t index, CONTROL_PROTOCOL__dvm_options_t dvm,
+ static hailo_status set_power_measurement(Device &device, hailo_measurement_buffer_index_t buffer_index, CONTROL_PROTOCOL__dvm_options_t dvm,
CONTROL_PROTOCOL__power_measurement_types_t measurement_type);
- static hailo_status get_power_measurement(Device &device, uint32_t index, bool should_clear,
+ static hailo_status get_power_measurement(Device &device, hailo_measurement_buffer_index_t buffer_index, bool should_clear,
hailo_power_measurement_data_t *measurement_data);
- static hailo_status start_power_measurement(Device &device, uint32_t delay_milliseconds,
+ static hailo_status start_power_measurement(Device &device,
CONTROL_PROTOCOL__averaging_factor_t averaging_factor, CONTROL_PROTOCOL__sampling_period_t sampling_period);
static hailo_status stop_power_measurement(Device &device);
CONTROL_PROTOCOL__context_switch_context_info_single_control_t *context_info);
static hailo_status change_context_switch_status(Device &device,
CONTROL_PROTOCOL__CONTEXT_SWITCH_STATUS_t state_machine_status,
- uint8_t network_group_index);
+ uint8_t network_group_index, uint16_t dynamic_batch_size);
};
} /* namespace hailort */
request->parameters.context_switch_set_context_info_request.is_last_control_per_context =
context_info->is_last_control_per_context;
- /* context cfg base address */
- request->parameters.context_switch_set_context_info_request.context_cfg_base_address_length =
- BYTE_ORDER__htonl(sizeof(request->parameters.context_switch_set_context_info_request.context_cfg_base_address));
- memcpy(&(request->parameters.context_switch_set_context_info_request.context_cfg_base_address),
- &(context_info->context_cfg_base_address),
- sizeof(request->parameters.context_switch_set_context_info_request.context_cfg_base_address));
-
- /* context total descriptors */
- request->parameters.context_switch_set_context_info_request.context_cfg_total_descriptors_length =
- BYTE_ORDER__htonl(sizeof(request->parameters.context_switch_set_context_info_request.context_cfg_total_descriptors));
- memcpy(&(request->parameters.context_switch_set_context_info_request.context_cfg_total_descriptors),
- &(context_info->context_cfg_total_descriptors),
- sizeof(request->parameters.context_switch_set_context_info_request.context_cfg_total_descriptors));
+ /* cfg_channels_count */
+ request->parameters.context_switch_set_context_info_request.cfg_channels_count_length =
+ BYTE_ORDER__htonl(sizeof(request->parameters.context_switch_set_context_info_request.cfg_channels_count));
+ request->parameters.context_switch_set_context_info_request.cfg_channels_count = context_info->cfg_channels_count;
+
+ /* context cfg buffer info */
+ request->parameters.context_switch_set_context_info_request.config_buffer_infos_length =
+ BYTE_ORDER__htonl(sizeof(request->parameters.context_switch_set_context_info_request.config_buffer_infos));
+ memcpy(&(request->parameters.context_switch_set_context_info_request.config_buffer_infos),
+ &(context_info->config_buffer_infos),
+ sizeof(request->parameters.context_switch_set_context_info_request.config_buffer_infos));
/* context unused stream index */
request->parameters.context_switch_set_context_info_request.context_stream_remap_data_length =
HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_change_context_switch_status_request(
CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence,
- CONTROL_PROTOCOL__CONTEXT_SWITCH_STATUS_t state_machine_status, uint8_t application_index)
+ CONTROL_PROTOCOL__CONTEXT_SWITCH_STATUS_t state_machine_status, uint8_t application_index,
+ uint16_t dynamic_batch_size)
{
HAILO_COMMON_STATUS_t status = HAILO_COMMON_STATUS__UNINITIALIZED;
size_t local_request_size = 0;
/* Header */
local_request_size = CONTROL_PROTOCOL__REQUEST_BASE_SIZE +
sizeof(CONTROL_PROTOCOL__change_context_switch_status_request_t);
- control_protocol__pack_request_header(request, sequence, HAILO_CONTROL_OPCODE_CHANGE_CONTEXT_SWITCH_STATUS, 2);
+ control_protocol__pack_request_header(request, sequence, HAILO_CONTROL_OPCODE_CHANGE_CONTEXT_SWITCH_STATUS, 3);
/* state_machine_status */
request->parameters.change_context_switch_status_request.state_machine_status_length =
request->parameters.change_context_switch_status_request.application_index_length =
BYTE_ORDER__htonl(sizeof(request->parameters.change_context_switch_status_request.application_index));
request->parameters.change_context_switch_status_request.application_index = application_index;
+
+ /* dynamic_batch_size */
+ request->parameters.change_context_switch_status_request.dynamic_batch_size_length =
+ BYTE_ORDER__htonl(sizeof(request->parameters.change_context_switch_status_request.dynamic_batch_size));
+ request->parameters.change_context_switch_status_request.dynamic_batch_size = dynamic_batch_size;
*request_size = local_request_size;
status = HAILO_COMMON_STATUS__SUCCESS;
}
HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_switch_application_request(
CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence,
- uint8_t application_index)
+ uint8_t application_index, uint16_t dynamic_batch_size)
{
HAILO_COMMON_STATUS_t status = HAILO_COMMON_STATUS__UNINITIALIZED;
size_t local_request_size = 0;
request->parameters.switch_application_request.application_index_length =
BYTE_ORDER__htonl(sizeof(request->parameters.switch_application_request.application_index));
request->parameters.switch_application_request.application_index = application_index;
+
+ /* dynamic_batch_size */
+ request->parameters.switch_application_request.dynamic_batch_size_length =
+ BYTE_ORDER__htonl(sizeof(request->parameters.switch_application_request.dynamic_batch_size));
+ request->parameters.switch_application_request.dynamic_batch_size = dynamic_batch_size;
*request_size = local_request_size;
status = HAILO_COMMON_STATUS__SUCCESS;
} CONTEXT_SWITCH__context_control_slicing_data_t;
typedef struct {
- uint64_t context_cfg_base_address[CONTROL_PROTOCOL__MAX_CFG_CHANNELS];
- uint16_t context_total_descriptors[CONTROL_PROTOCOL__MAX_CFG_CHANNELS];
+ uint8_t cfg_channels_count;
+ CONTROL_PROTOCOL__host_buffer_info_t config_buffer_infos[CONTROL_PROTOCOL__MAX_CFG_CHANNELS];
uint32_t context_network_data_length;
CONTROL_PROTOCOL__stream_remap_data_t context_stream_remap_data;
uint8_t context_network_data[CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_MAX_SIZE];
size_t *request_size, uint32_t sequence, uint8_t context_index, uint16_t action_list_offset);
HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_change_context_switch_status_request(
CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence,
- CONTROL_PROTOCOL__CONTEXT_SWITCH_STATUS_t state_machine_status, uint8_t application_index);
+ CONTROL_PROTOCOL__CONTEXT_SWITCH_STATUS_t state_machine_status, uint8_t application_index,
+ uint16_t dynamic_batch_size);
HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_wd_enable(
CONTROL_PROTOCOL__request_t *request,
size_t *request_size,
HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_d2h_event_manager_send_host_info_event_request( CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence,
uint8_t event_priority);
HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_switch_application_request(CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence,
- uint8_t application_index);
+ uint8_t application_index, uint16_t dynamic_batch_size);
HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_get_chip_temperature_request(CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence);
HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_read_board_config(CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, uint32_t address, uint32_t data_length);
HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_write_board_config_request(CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, uint32_t address, const uint8_t *data, uint32_t data_length);
{
Expected<std::unique_ptr<CoreInputStream>> CoreInputStream::create(Device &device,
- uint8_t channel_index, const LayerInfo &edge_layer,
- uint16_t batch_size, EventPtr network_group_activated_event, LatencyMeterPtr latency_meter)
+ std::shared_ptr<VdmaChannel> channel, const LayerInfo &edge_layer,
+ uint16_t batch_size, EventPtr network_group_activated_event)
{
hailo_status status = HAILO_UNINITIALIZED;
CoreDevice *core_device = reinterpret_cast<CoreDevice*>(&device);
std::unique_ptr<CoreInputStream> local_stream(new (std::nothrow) CoreInputStream(*core_device,
- channel_index, edge_layer, std::move(network_group_activated_event), batch_size,
- latency_meter, DEFAULT_TRANSFER_TIMEOUT, status));
+ std::move(channel), edge_layer, std::move(network_group_activated_event), batch_size,
+ DEFAULT_TRANSFER_TIMEOUT, status));
CHECK((nullptr != local_stream), make_unexpected(HAILO_OUT_OF_HOST_MEMORY));
CHECK_SUCCESS_AS_EXPECTED(status);
CoreInputStream::CoreInputStream(
CoreDevice &device,
- uint8_t channel_index,
+ std::shared_ptr<VdmaChannel> channel,
const LayerInfo &edge_layer,
EventPtr network_group_activated_event,
uint16_t batch_size,
- LatencyMeterPtr latency_meter,
const std::chrono::milliseconds &transfer_timeout,
hailo_status &status) :
- VdmaInputStream(device, channel_index, edge_layer, network_group_activated_event,
- batch_size, latency_meter, transfer_timeout, HAILO_STREAM_INTERFACE_CORE, status)
+ VdmaInputStream(device, std::move(channel), edge_layer, network_group_activated_event,
+ batch_size, transfer_timeout, HAILO_STREAM_INTERFACE_CORE, status)
{}
Expected<std::unique_ptr<CoreOutputStream>> CoreOutputStream::create(Device &device,
- uint8_t channel_index, const LayerInfo &edge_layer, uint16_t batch_size,
- EventPtr network_group_activated_event, LatencyMeterPtr latency_meter)
+ std::shared_ptr<VdmaChannel> channel, const LayerInfo &edge_layer,
+ uint16_t batch_size, EventPtr network_group_activated_event)
{
hailo_status status = HAILO_UNINITIALIZED;
CHECK_AS_EXPECTED(device.get_type() == Device::Type::CORE, HAILO_INTERNAL_FAILURE,
CoreDevice *core_device = reinterpret_cast<CoreDevice*>(&device);
std::unique_ptr<CoreOutputStream> local_stream(new (std::nothrow) CoreOutputStream(*core_device,
- channel_index, edge_layer, std::move(network_group_activated_event),
- batch_size, latency_meter, DEFAULT_TRANSFER_TIMEOUT, status));
+ std::move(channel), edge_layer, std::move(network_group_activated_event),
+ batch_size, DEFAULT_TRANSFER_TIMEOUT, status));
CHECK((nullptr != local_stream), make_unexpected(HAILO_OUT_OF_HOST_MEMORY));
CHECK_SUCCESS_AS_EXPECTED(status);
CoreOutputStream::CoreOutputStream(
CoreDevice &device,
- uint8_t channel_index,
+ std::shared_ptr<VdmaChannel> channel,
const LayerInfo &edge_layer,
EventPtr network_group_activated_event,
uint16_t batch_size,
- LatencyMeterPtr latency_meter,
const std::chrono::milliseconds &transfer_timeout,
hailo_status &status) :
- VdmaOutputStream(device, channel_index, edge_layer,
- network_group_activated_event, batch_size, latency_meter, transfer_timeout, status)
+ VdmaOutputStream(device, std::move(channel), edge_layer,
+ network_group_activated_event, batch_size, transfer_timeout, status)
{}
} /* namespace hailort */
CoreInputStream(CoreInputStream &&other) = default;
virtual ~CoreInputStream() = default;
- static Expected<std::unique_ptr<CoreInputStream>> create(Device &device, uint8_t channel_index,
- const LayerInfo &edge_layer, uint16_t batch_size, EventPtr network_group_activated_event,
- LatencyMeterPtr latency_meter = nullptr);
+ static Expected<std::unique_ptr<CoreInputStream>> create(Device &device,
+ std::shared_ptr<VdmaChannel> channel, const LayerInfo &edge_layer, uint16_t batch_size,
+ EventPtr network_group_activated_event);
virtual hailo_stream_interface_t get_interface() const override { return HAILO_STREAM_INTERFACE_CORE; }
private:
CoreInputStream(
CoreDevice &device,
- uint8_t channel_index,
+ std::shared_ptr<VdmaChannel> channel,
const LayerInfo &edge_layer,
EventPtr network_group_activated_event,
uint16_t batch_size,
- LatencyMeterPtr latency_meter,
const std::chrono::milliseconds &transfer_timeout,
hailo_status &status);
};
CoreOutputStream(CoreOutputStream &&other) = default;
virtual ~CoreOutputStream() = default;
- static Expected<std::unique_ptr<CoreOutputStream>> create(Device &device, uint8_t channel_index,
- const LayerInfo &edge_layer, uint16_t batch_size, EventPtr network_group_activated_event,
- LatencyMeterPtr latency_meter);
+ static Expected<std::unique_ptr<CoreOutputStream>> create(Device &device,
+ std::shared_ptr<VdmaChannel> channel, const LayerInfo &edge_layer, uint16_t batch_size,
+ EventPtr network_group_activated_event);
virtual hailo_stream_interface_t get_interface() const override { return HAILO_STREAM_INTERFACE_CORE; }
private:
explicit CoreOutputStream(
CoreDevice &device,
- uint8_t channel_index,
+ std::shared_ptr<VdmaChannel> channel,
const LayerInfo &edge_layer,
EventPtr network_group_activated_event,
uint16_t batch_size,
- LatencyMeterPtr latency_meter,
const std::chrono::milliseconds &transfer_timeout,
hailo_status &status);
};
return res;
}
-hailo_status Device::start_power_measurement(uint32_t delay_milliseconds, hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period)
+hailo_status Device::start_power_measurement(uint32_t /*unused*/, hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period)
{
- return Control::start_power_measurement(*this, delay_milliseconds, static_cast<CONTROL_PROTOCOL__averaging_factor_t>(averaging_factor),
- static_cast<CONTROL_PROTOCOL__sampling_period_t>(sampling_period));
+ // TODO: Remove deprecated function
+ LOGGER__WARNING("'Device::start_power_measurement(uint32_t unused, hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period)' is deprecated. "\
+ "One should use ''Device::start_power_measurement(hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period)");
+ return start_power_measurement(averaging_factor, sampling_period);
}
hailo_status Device::set_power_measurement(uint32_t index, hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type)
{
- return Control::set_power_measurement(*this, index, static_cast<CONTROL_PROTOCOL__dvm_options_t>(dvm), static_cast<CONTROL_PROTOCOL__power_measurement_types_t>(measurement_type));
+ // TODO: Remove deprecated function
+ LOGGER__WARNING("'Device::set_power_measurement(uint32_t index, hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type)' is deprecated. "\
+ "One should use ''Device::set_power_measurement(hailo_measurement_buffer_index_t buffer_index, hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type)");
+ return set_power_measurement(static_cast<hailo_measurement_buffer_index_t>(index), dvm, measurement_type);
}
Expected<hailo_power_measurement_data_t> Device::get_power_measurement(uint32_t index, bool should_clear)
+{
+ // TODO: Remove deprecated function
+ LOGGER__WARNING("'Device::get_power_measurement(uint32_t index, bool should_clear)' is deprecated. "\
+ "One should use ''Device::set_power_measurement(hailo_measurement_buffer_index_t buffer_index, bool should_clear)");
+ return get_power_measurement(static_cast<hailo_measurement_buffer_index_t>(index), should_clear);
+}
+
+hailo_status Device::start_power_measurement(hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period)
+{
+ return Control::start_power_measurement(*this, static_cast<CONTROL_PROTOCOL__averaging_factor_t>(averaging_factor),
+ static_cast<CONTROL_PROTOCOL__sampling_period_t>(sampling_period));
+}
+
+hailo_status Device::set_power_measurement(hailo_measurement_buffer_index_t buffer_index, hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type)
+{
+ return Control::set_power_measurement(*this, buffer_index, static_cast<CONTROL_PROTOCOL__dvm_options_t>(dvm), static_cast<CONTROL_PROTOCOL__power_measurement_types_t>(measurement_type));
+}
+
+Expected<hailo_power_measurement_data_t> Device::get_power_measurement(hailo_measurement_buffer_index_t buffer_index, bool should_clear)
{
hailo_power_measurement_data_t measurement_data = {};
- auto status = Control::get_power_measurement(*this, index, should_clear, &measurement_data);
+ auto status = Control::get_power_measurement(*this, buffer_index, should_clear, &measurement_data);
CHECK_SUCCESS_AS_EXPECTED(status);
return measurement_data;
}
return final_action_list.release();
}
+hailo_status Device::set_context_action_list_timestamp_batch(uint16_t batch_index)
+{
+ static const bool ENABLE_USER_CONFIG = true;
+ return Control::config_context_switch_timestamp(*this, batch_index, ENABLE_USER_CONFIG);
+}
+
} /* namespace hailort */
return reset_impl(reset_type);
}
-hailo_status DeviceBase::set_notification_callback(NotificationCallback func, hailo_notification_id_t notification_id, void *opaque)
+hailo_status DeviceBase::set_notification_callback(const NotificationCallback &func, hailo_notification_id_t notification_id, void *opaque)
{
CHECK((0 <= notification_id) && (HAILO_NOTIFICATION_ID_COUNT > notification_id), HAILO_INVALID_ARGUMENT,
"Notification id value is invalid");
CHECK_ARG_NOT_NULL(func);
+ auto func_ptr = make_shared_nothrow<NotificationCallback>(func);
+ CHECK_NOT_NULL(func_ptr, HAILO_OUT_OF_HOST_MEMORY);
+
const std::lock_guard<std::mutex> lock(m_callbacks_lock);
- m_d2h_callbacks[notification_id].func = func;
+ m_d2h_callbacks[notification_id].func = func_ptr;
m_d2h_callbacks[notification_id].opaque = opaque;
return HAILO_SUCCESS;
}
LOGGER__INFO("[{}] Got notification from fw with id: {}", device_id, hailo_notification_id);
- NotificationCallback callback_func = nullptr;
+ std::shared_ptr<NotificationCallback> callback_func = nullptr;
void *callback_opaque = nullptr;
{
const std::lock_guard<std::mutex> lock(m_callbacks_lock);
callback_notification.sequence = notification.header.sequence;
static_assert(sizeof(callback_notification.body) == sizeof(notification.message_parameters), "D2H notification size mismatch");
memcpy(&callback_notification.body, ¬ification.message_parameters, sizeof(notification.message_parameters));
- callback_func(*this, callback_notification, callback_opaque);
+ (*callback_func)(*this, callback_notification, callback_opaque);
}
}
}
virtual Expected<ConfiguredNetworkGroupVector> configure(Hef &hef,
const NetworkGroupsParamsMap &configure_params={}) override;
virtual hailo_status reset(hailo_reset_device_mode_t mode) override;
- virtual hailo_status set_notification_callback(NotificationCallback func, hailo_notification_id_t notification_id, void *opaque) override;
+ virtual hailo_status set_notification_callback(const NotificationCallback &func, hailo_notification_id_t notification_id, void *opaque) override;
virtual hailo_status remove_notification_callback(hailo_notification_id_t notification_id) override;
virtual void activate_notifications(const std::string &device_id);
virtual void start_notification_fetch_thread(D2hEventQueue *write_queue);
Expected<firmware_type_t> get_fw_type();
typedef struct {
- NotificationCallback func;
+ std::shared_ptr<NotificationCallback> func;
void *opaque;
} d2h_notification_callback_t;
return HAILO_SUCCESS;
}
-hailo_status EthernetInputStream::activate_stream()
+// Note: Ethernet streams don't work with dynamic batch sizes
+hailo_status EthernetInputStream::activate_stream(uint16_t /* dynamic_batch_size */)
{
hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__config_stream_params_t params = {};
return HAILO_SUCCESS;
}
-hailo_status EthernetOutputStream::activate_stream()
+// Note: Ethernet streams don't work with dynamic batch sizes
+hailo_status EthernetOutputStream::activate_stream(uint16_t /* dynamic_batch_size */)
{
hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__config_stream_params_t params = {};
const LayerInfo &edge_layer, const hailo_eth_input_stream_params_t ¶ms, EventPtr network_group_activated_event);
uint16_t get_remote_port();
- virtual hailo_status activate_stream() override;
+ virtual hailo_status activate_stream(uint16_t dynamic_batch_size) override;
virtual hailo_status deactivate_stream() override;
virtual hailo_stream_interface_t get_interface() const override { return HAILO_STREAM_INTERFACE_ETH; }
virtual std::chrono::milliseconds get_timeout() const override;
static Expected<std::unique_ptr<EthernetOutputStream>> create(Device &device, const LayerInfo &edge_layer,
const hailo_eth_output_stream_params_t ¶ms, EventPtr network_group_activated_event);
- virtual hailo_status activate_stream() override;
+ virtual hailo_status activate_stream(uint16_t dynamic_batch_size) override;
virtual hailo_status deactivate_stream() override;
virtual hailo_stream_interface_t get_interface() const override { return HAILO_STREAM_INTERFACE_ETH; }
virtual std::chrono::milliseconds get_timeout() const override;
// * Hence, SHUTDOWN_INDEX must come before WAITABLE_INDEX!
static const size_t SHUTDOWN_INDEX = 0;
static const size_t WAITABLE_INDEX = 1;
- #if defined(_MSC_VER)
- using WaitHandleArray = std::array<underlying_handle_t, 2>;
+ #if defined(_MSC_VER) || defined(__QNX__)
+ using WaitHandleArray = std::array<underlying_waitable_handle_t, 2>;
#else
using WaitHandleArray = std::array<struct pollfd, 2>;
#endif
return HAILO_SUCCESS;
}
-hailo_status hailo_start_power_measurement(hailo_device device, uint32_t delay_milliseconds,
+hailo_status hailo_start_power_measurement(hailo_device device,
hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period)
{
CHECK_ARG_NOT_NULL(device);
- auto status = Control::start_power_measurement(*reinterpret_cast<Device*>(device), delay_milliseconds, static_cast<CONTROL_PROTOCOL__averaging_factor_t>(averaging_factor), static_cast<CONTROL_PROTOCOL__sampling_period_t>(sampling_period));
+ auto status = Control::start_power_measurement(*reinterpret_cast<Device*>(device), static_cast<CONTROL_PROTOCOL__averaging_factor_t>(averaging_factor), static_cast<CONTROL_PROTOCOL__sampling_period_t>(sampling_period));
CHECK_SUCCESS(status);
return HAILO_SUCCESS;
}
-hailo_status hailo_set_power_measurement(hailo_device device, uint32_t index,
+hailo_status hailo_set_power_measurement(hailo_device device, hailo_measurement_buffer_index_t buffer_index,
hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type)
{
CHECK_ARG_NOT_NULL(device);
- auto status = Control::set_power_measurement(*reinterpret_cast<Device*>(device), index, static_cast<CONTROL_PROTOCOL__dvm_options_t>(dvm), static_cast<CONTROL_PROTOCOL__power_measurement_types_t>(measurement_type));
+ auto status = Control::set_power_measurement(*reinterpret_cast<Device*>(device), buffer_index, static_cast<CONTROL_PROTOCOL__dvm_options_t>(dvm), static_cast<CONTROL_PROTOCOL__power_measurement_types_t>(measurement_type));
CHECK_SUCCESS(status);
return HAILO_SUCCESS;
}
-hailo_status hailo_get_power_measurement(hailo_device device, uint32_t index, bool should_clear,
+hailo_status hailo_get_power_measurement(hailo_device device, hailo_measurement_buffer_index_t buffer_index, bool should_clear,
hailo_power_measurement_data_t *measurement_data)
{
CHECK_ARG_NOT_NULL(device);
CHECK_ARG_NOT_NULL(measurement_data);
- auto status = Control::get_power_measurement(*reinterpret_cast<Device*>(device), index, should_clear, measurement_data);
+ auto status = Control::get_power_measurement(*reinterpret_cast<Device*>(device), buffer_index, should_clear, measurement_data);
CHECK_SUCCESS(status);
return HAILO_SUCCESS;
}
return HAILO_SUCCESS;
}
-hailo_status hailo_get_latency_measurement_from_network_group(hailo_configured_network_group configured_network_group,
- hailo_latency_measurement_result_t *result)
+HAILORTAPI hailo_status hailo_get_latency_measurement(hailo_configured_network_group configured_network_group,
+ const char *network_name, hailo_latency_measurement_result_t *result)
{
- LOGGER__WARNING("'hailo_get_latency_measurement_from_network_group' is deprecated. One shuold use 'hailo_get_latency_measurement()'.");
CHECK_ARG_NOT_NULL(configured_network_group);
CHECK_ARG_NOT_NULL(result);
- auto latency_result = ((ConfiguredNetworkGroup*)configured_network_group)->get_latency_measurement();
+ std::string network_name_str = (nullptr == network_name) ? "" : network_name;
+
+ auto latency_result = ((ConfiguredNetworkGroup*)configured_network_group)->get_latency_measurement(network_name_str);
CHECK_EXPECTED_AS_STATUS(latency_result);
hailo_latency_measurement_result_t local_result {};
return HAILO_SUCCESS;
}
-HAILORTAPI hailo_status hailo_get_latency_measurement(hailo_configured_network_group configured_network_group,
- const char *network_name, hailo_latency_measurement_result_t *result)
+hailo_status hailo_set_scheduler_timeout(hailo_configured_network_group configured_network_group,
+ uint32_t timeout_ms, const char *network_name)
{
CHECK_ARG_NOT_NULL(configured_network_group);
- CHECK_ARG_NOT_NULL(result);
std::string network_name_str = (nullptr == network_name) ? "" : network_name;
+ return ((ConfiguredNetworkGroup*)configured_network_group)->set_scheduler_timeout(std::chrono::milliseconds(timeout_ms), network_name_str);
+}
- auto latency_result = ((ConfiguredNetworkGroup*)configured_network_group)->get_latency_measurement(network_name_str);
- CHECK_EXPECTED_AS_STATUS(latency_result);
-
- hailo_latency_measurement_result_t local_result {};
- local_result.avg_hw_latency_ms = std::chrono::duration<double, std::milli>(latency_result->avg_hw_latency).count();
+hailo_status hailo_set_scheduler_threshold(hailo_configured_network_group configured_network_group,
+ uint32_t threshold, const char *network_name)
+{
+ CHECK_ARG_NOT_NULL(configured_network_group);
- *result = local_result;
- return HAILO_SUCCESS;
+ std::string network_name_str = (nullptr == network_name) ? "" : network_name;
+ return ((ConfiguredNetworkGroup*)configured_network_group)->set_scheduler_threshold(threshold, network_name_str);
}
hailo_status hailo_calculate_eth_input_rate_limits(hailo_hef hef, const char *network_group_name, uint32_t fps,
return HAILO_SUCCESS;
}
-// TODO (HRT-6080): Remove deprecated function
-hailo_status hailo_create_input_transformer(const hailo_stream_info_t *stream_info,
- const hailo_transform_params_t *transform_params, hailo_input_transform_context *transformer)
-{
- CHECK_ARG_NOT_NULL(stream_info);
- CHECK_ARG_NOT_NULL(transform_params);
- CHECK_ARG_NOT_NULL(transformer);
-
- LOGGER__WARNING("'hailo_create_input_transformer' is deprecated. One shold use 'hailo_create_input_transform_context'");
-
- auto local_transformer = InputTransformContext::create(*stream_info, *transform_params);
- CHECK_EXPECTED_AS_STATUS(local_transformer);
-
- *transformer = reinterpret_cast<hailo_input_transform_context>(local_transformer.release().release());
- return HAILO_SUCCESS;
-}
-
-// TODO (HRT-6080): Remove deprecated function
-hailo_status hailo_release_input_transformer(hailo_input_transform_context transformer)
-{
- CHECK_ARG_NOT_NULL(transformer);
-
- LOGGER__WARNING("'hailo_release_input_transformer' is deprecated. One shold use 'hailo_release_input_transform_context'");
-
- delete reinterpret_cast<InputTransformContext*>(transformer);
- return HAILO_SUCCESS;
-}
-
-// TODO (HRT-6080): Remove deprecated function
-hailo_status hailo_transform_frame_by_input_transformer(hailo_input_transform_context transformer,
- const void *src, size_t src_size, void *dst, size_t dst_size)
-{
- CHECK_ARG_NOT_NULL(transformer);
- CHECK_ARG_NOT_NULL(src);
- CHECK_ARG_NOT_NULL(dst);
-
- LOGGER__WARNING("'hailo_transform_frame_by_input_transformer' is deprecated. One shold use 'hailo_transform_frame_by_input_transform_context'");
-
- MemoryView dst_buffer(dst, dst_size);
- auto status = reinterpret_cast<InputTransformContext*>(transformer)->transform(
- MemoryView::create_const(src, src_size), dst_buffer);
- CHECK_SUCCESS(status);
- return HAILO_SUCCESS;
-}
-
-// TODO (HRT-6080): Remove deprecated function
-hailo_status hailo_create_output_transformer(const hailo_stream_info_t *stream_info,
- const hailo_transform_params_t *transform_params, hailo_output_transform_context *transformer)
-{
- CHECK_ARG_NOT_NULL(stream_info);
- CHECK_ARG_NOT_NULL(transform_params);
- CHECK_ARG_NOT_NULL(transformer);
-
- LOGGER__WARNING("'hailo_create_output_transformer' is deprecated. One shold use 'hailo_create_output_transform_context'");
-
- auto local_transformer = OutputTransformContext::create(*stream_info, *transform_params);
- CHECK_EXPECTED_AS_STATUS(local_transformer);
-
- *transformer = reinterpret_cast<hailo_output_transform_context>(local_transformer.release().release());
- return HAILO_SUCCESS;
-}
-
-// TODO (HRT-6080): Remove deprecated function
-hailo_status hailo_release_output_transformer(hailo_output_transform_context transformer)
-{
- CHECK_ARG_NOT_NULL(transformer);
-
- LOGGER__WARNING("'hailo_release_output_transformer' is deprecated. One shold use 'hailo_release_output_transform_context'");
-
- delete reinterpret_cast<OutputTransformContext*>(transformer);
- return HAILO_SUCCESS;
-}
-
-// TODO (HRT-6080): Remove deprecated function
-hailo_status hailo_transform_frame_by_output_transformer(hailo_output_transform_context transformer,
- const void *src, size_t src_size, void *dst, size_t dst_size)
-{
- CHECK_ARG_NOT_NULL(transformer);
- CHECK_ARG_NOT_NULL(src);
- CHECK_ARG_NOT_NULL(dst);
-
- LOGGER__WARNING("'hailo_transform_frame_by_output_transformer' is deprecated. One shold use 'hailo_transform_frame_by_output_transform_context'");
-
- MemoryView dst_buffer(dst, dst_size);
- auto status = reinterpret_cast<OutputTransformContext*>(transformer)->transform(MemoryView::create_const(src,
- src_size), dst_buffer);
- CHECK_SUCCESS(status);
- return HAILO_SUCCESS;
-}
-
hailo_status hailo_create_demuxer_by_stream(hailo_output_stream stream,
const hailo_demux_params_t *demux_params, hailo_output_demuxer *demuxer)
{
const uint32_t HailoRTCommon::MAX_DEFUSED_LAYER_COUNT;
const size_t HailoRTCommon::HW_DATA_ALIGNMENT;
const uint64_t HailoRTCommon::NMS_DELIMITER;
+const uint64_t HailoRTCommon::NMS_DUMMY_DELIMITER;
} /* namespace hailort */
};
-#define HAILO_DEFAULT_PARTIAL_NETWORK_NAME (std::string("default_network_name"))
#define HAILO_DEFAULT_NETWORK_NAME_QUALIFIER (std::string("/"))
+
class HailoRTDefaults
{
public:
{
std::string default_network_name = net_group_name +
HAILO_DEFAULT_NETWORK_NAME_QUALIFIER +
- HAILO_DEFAULT_PARTIAL_NETWORK_NAME;
+ net_group_name;
return default_network_name;
}
- static std::string get_partial_network_name()
- {
- return HAILO_DEFAULT_PARTIAL_NETWORK_NAME;
- }
-
static hailo_format_t expand_auto_format(const hailo_format_t &host_format, const hailo_format_t &hw_format)
{
auto host_format_copy = host_format;
auto sorted_output_names = HefUtils::get_sorted_output_names(*network_group);
CHECK_EXPECTED_AS_STATUS(sorted_output_names);
- std::vector<std::string> sorted_partial_network_names;
+ std::vector<std::string> sorted_network_names;
if (supported_features.multi_network_support) {
- sorted_partial_network_names.reserve(network_group->networks_names().size());
+ sorted_network_names.reserve(network_group->networks_names().size());
for (auto &partial_network_name : network_group->networks_names()) {
- sorted_partial_network_names.push_back(partial_network_name);
+ auto network_name = HefUtils::get_network_name(*network_group, partial_network_name);
+ sorted_network_names.push_back(network_name);
}
} else {
- sorted_partial_network_names.push_back(HAILO_DEFAULT_PARTIAL_NETWORK_NAME);
+ sorted_network_names.push_back(HailoRTDefaults::get_network_name(network_group->network_group_metadata().network_group_name()));
}
NetworkGroupMetadata metadata(network_group->network_group_metadata().network_group_name(),
- layer_infos.release(), sorted_output_names.release(), supported_features, sorted_partial_network_names);
+ layer_infos.release(), sorted_output_names.release(), supported_features, sorted_network_names);
m_network_group_metadata.emplace(
network_group->network_group_metadata().network_group_name(), metadata);
}
const std::vector<ProtoHEFExtension> &hef_extensions, const ProtoHEFIncludedFeatures &included_features,
const std::vector<ProtoHEFOptionalExtension> &hef_optional_extensions)
{
- NetworkGroupSupportedFeatures supported_features = {};
+ NetworkGroupSupportedFeatures supported_features{};
supported_features.padded_ddr_buffers = check_hef_extension(ProtoHEFExtensionType::PADDED_DDR_BUFFERS, header,
hef_extensions, included_features);
supported_features.multi_network_support = check_hef_optional_extension(ProtoHEFExtensionType::MULTI_NETWORK_VARIABLE_BATCH_SIZE,
header, hef_optional_extensions);
- supported_features.multi_context = check_hef_extension(ProtoHEFExtensionType::IS_MULTI_CONTEXTS, header,
+ supported_features.multi_context = check_hef_extension(ProtoHEFExtensionType::IS_MULTI_CONTEXTS, header,
hef_extensions, included_features);
+ supported_features.preliminary_run_asap = check_hef_extension(ProtoHEFExtensionType::PRELIMINARY_RUN_ASAP,
+ header, hef_extensions, included_features);
return supported_features;
}
}
Expected<std::vector<hailo_stream_info_t>> Hef::Impl::get_input_stream_infos(const std::string &net_group_name,
- const std::string &partial_network_name)
+ const std::string &network_name)
{
auto network_group_metadata = get_network_group_metadata(net_group_name);
CHECK_EXPECTED(network_group_metadata);
- return network_group_metadata->get_input_stream_infos(partial_network_name);
+ return network_group_metadata->get_input_stream_infos(network_name);
}
Expected<std::vector<hailo_stream_info_t>> Hef::Impl::get_output_stream_infos(const std::string &net_group_name,
- const std::string &partial_network_name)
+ const std::string &network_name)
{
auto network_group_metadata = get_network_group_metadata(net_group_name);
CHECK_EXPECTED(network_group_metadata);
- return network_group_metadata->get_output_stream_infos(partial_network_name);
+ return network_group_metadata->get_output_stream_infos(network_name);
}
Expected<std::vector<hailo_stream_info_t>> Hef::Impl::get_all_stream_infos(const std::string &net_group_name,
- const std::string &partial_network_name)
+ const std::string &network_name)
{
auto network_group_metadata = get_network_group_metadata(net_group_name);
CHECK_EXPECTED(network_group_metadata);
- return network_group_metadata->get_all_stream_infos(partial_network_name);
+ return network_group_metadata->get_all_stream_infos(network_name);
}
Expected<std::vector<hailo_network_info_t>> Hef::Impl::get_network_infos(const std::string &net_group_name)
}
Expected<std::vector<hailo_vstream_info_t>> Hef::Impl::get_input_vstream_infos(const std::string &net_group_name,
- const std::string &partial_network_name)
+ const std::string &network_name)
{
auto network_group_metadata = get_network_group_metadata(net_group_name);
CHECK_EXPECTED(network_group_metadata);
- return network_group_metadata->get_input_vstream_infos(partial_network_name);
+ return network_group_metadata->get_input_vstream_infos(network_name);
}
Expected<std::vector<hailo_vstream_info_t>> Hef::Impl::get_output_vstream_infos(const std::string &net_group_name,
- const std::string &partial_network_name)
+ const std::string &network_name)
{
auto network_group_metadata = get_network_group_metadata(net_group_name);
CHECK_EXPECTED(network_group_metadata);
- return network_group_metadata->get_output_vstream_infos(partial_network_name);
+ return network_group_metadata->get_output_vstream_infos(network_name);
}
Expected<std::vector<hailo_vstream_info_t>> Hef::Impl::get_all_vstream_infos(const std::string &net_group_name,
- const std::string &partial_network_name)
+ const std::string &network_name)
{
auto network_group_metadata = get_network_group_metadata(net_group_name);
CHECK_EXPECTED(network_group_metadata);
- return network_group_metadata->get_all_vstream_infos(partial_network_name);
+ return network_group_metadata->get_all_vstream_infos(network_name);
}
const std::vector<ProtoHEFNetworkGroupPtr>& Hef::Impl::network_groups() const
network_group_name = m_groups[0]->network_group_metadata().network_group_name();
LOGGER__INFO("No name was given. Addressing all networks of default network_group: {}",
network_group_name);
- return std::make_pair(network_group_name, HAILO_DEFAULT_PARTIAL_NETWORK_NAME);
- } else if (HAILO_DEFAULT_PARTIAL_NETWORK_NAME == name) {
- /* HAILO_DEFAULT_PARTIAL_NETWORK_NAME is passed for HEFs that doesnt support network groups.
- We know that multiple networks_groups in single HEF is'nt supported for those HEFs. */
- network_group_name = m_groups[0]->network_group_metadata().network_group_name();
- return std::make_pair(network_group_name, HAILO_DEFAULT_PARTIAL_NETWORK_NAME);
+ auto network_name = HailoRTDefaults::get_network_name(network_group_name);
+ return std::make_pair(network_group_name, network_name);
} else {
for (const auto &network_group : m_groups) {
network_group_name = network_group->network_group_metadata().network_group_name();
// Look for network_group with the given name
if (name == network_group_name) {
- return std::make_pair(network_group_name, HAILO_DEFAULT_PARTIAL_NETWORK_NAME);
+ auto network_name = HailoRTDefaults::get_network_name(network_group_name);
+ return std::make_pair(network_group_name, network_name);
}
// Look for network with the given name
for (const auto &partial_network_name : network_group->networks_names()) {
- auto full_network_name = network_group_name + HAILO_DEFAULT_NETWORK_NAME_QUALIFIER + partial_network_name;
+ auto full_network_name = HefUtils::get_network_name(network_group_name, partial_network_name);
if (name == full_network_name) {
- return std::make_pair(network_group_name, partial_network_name);
+ return std::make_pair(network_group_name, full_network_name);
}
}
// Handle case of deafult_network_name
- if (name == network_group_name + HAILO_DEFAULT_NETWORK_NAME_QUALIFIER + HAILO_DEFAULT_PARTIAL_NETWORK_NAME) {
- return std::make_pair(network_group_name, HAILO_DEFAULT_PARTIAL_NETWORK_NAME);
+ if (name == HailoRTDefaults::get_network_name(network_group_name)) {
+ return std::make_pair(network_group_name, name);
}
}
}
}
layer_info.name = info.name();
- layer_info.partial_network_name = partial_network_name;
+ layer_info.network_name = HefUtils::get_network_name(net_group, partial_network_name);
layer_info.is_mux = false;
layer_info.direction = direction;
layer_info.quant_info.limvals_max = info.numeric_info().limvals_max();
// This creates a new LayerInfo for the fused layer *for each defused layer*, even though they all share the same fused layer.
// TODO Make it so all defused layer reference the same LayerInfo of the fused layer.
LayerInfo fused_layer_info = {};
- status = fill_fused_nms_info(fused_layer, fused_layer_info, layer_info.quant_info, partial_network_name);
+ status = fill_fused_nms_info(fused_layer, fused_layer_info, layer_info.quant_info, layer_info.network_name);
CHECK_SUCCESS(status);
layer_info.fused_nms_layer.push_back(fused_layer_info);
break;
}
hailo_status HefUtils::fill_fused_nms_info(const ProtoHEFEdgeLayerFused &info, LayerInfo &layer_info,
- hailo_quant_info_t &defuse_quant_info, const std::string &partial_network_name)
+ hailo_quant_info_t &defuse_quant_info, const std::string &network_name)
{
auto base_info = info.layer_info().edge_layer_base();
auto format_order_exp = HailoRTDefaults::get_device_format_order(base_info.format());
return HAILO_INTERNAL_FAILURE;
}
layer_info.name = info.layer_info().name();
- layer_info.partial_network_name = partial_network_name;
+ layer_info.network_name = network_name;
layer_info.is_mux = false;
layer_info.direction = HAILO_D2H_STREAM;
// Due to bug in SDK quant info of fused layer is empty, so we use the quant info of the defused layer
}
layer_info.name = info.name();
- layer_info.partial_network_name = partial_network_name;
+ layer_info.network_name = HefUtils::get_network_name(net_group, partial_network_name);
layer_info.is_mux = true;
layer_info.predecessor.reserve(info.mux_data().number_of_predecessors());
layer_info.height_gcd = info.mux_data().height_gcd();
return std::make_pair(initial_l3_cut, initial_l3_offset);
}
+static uint32_t get_initial_credit_size(const ProtoHEFEdgeLayer &edge_layer_info)
+{
+ // On old HEFs the max shmifo is not defined, so 0 wil be returned and the firmware will choose the default value.
+ return edge_layer_info.layer_info().edge_layer_base().max_shmifo_size();
+}
+
static hailo_status fill_boundary_input_layer(CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
- uint8_t **context_meta_data_head_pointer, uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
- ContextSwitchChannelsParsingInfo &channels_parsing_info, ResourcesManager &resources_manager,
- const std::string &layer_name, uint8_t network_index)
+ uint8_t **context_meta_data_head_pointer, uint8_t stream_index, const ProtoHEFEdgeLayer &edge_layer_info,
+ const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config,
+ ContextSwitchChannelsParsingInfo &channels_parsing_info, ResourcesManager &resources_manager,
+ const std::string &layer_name, const std::string &network_name, uint8_t network_index,
+ uint32_t frame_credits_in_bytes)
{
auto channel_index = resources_manager.get_available_channel_index(
channels_parsing_info.H2D_channels_in_use, ChannelInfo::Type::BOUNDARY, VdmaChannel::Direction::H2D, layer_name);
CHECK_EXPECTED_AS_STATUS(channel_info);
channel_info->get().set_pcie_stream_index(stream_index);
+ auto vdma_channel = resources_manager.create_boundary_vdma_channel(channel_index.value(), frame_credits_in_bytes,
+ network_name, layer_name, VdmaChannel::Direction::H2D);
+ CHECK_EXPECTED_AS_STATUS(vdma_channel);
+
// Lock the channel for further use in this net_group
channels_parsing_info.H2D_channels_in_use.insert(channel_index.value());
LOGGER__DEBUG("Boundary input stream: {} h2d_pcie_channel: {}.", stream_index, channel_index.value());
/* Update metadata */
+ const uint32_t initial_credit_size = get_initial_credit_size(edge_layer_info);
auto status = HEF_METADATA__add_network_boundary_input_edge_layer(context_info,
context_meta_data_head_pointer, stream_index, channel_index.value(), network_index, nn_stream_config,
- DEFAULT_DESC_PAGE_SIZE);
+ vdma_channel.value()->get_page_size(), initial_credit_size);
CHECK_SUCCESS(status);
return HAILO_SUCCESS;
stream_index, src_context, dst_context, h2d_channel_index.value());
/* Update metadata */
+ const uint32_t initial_credit_size = get_initial_credit_size(*edge_layer_info);
return HEF_METADATA__add_inter_context_input_edge_layer(context_info, context_meta_data_head_pointer,
stream_index, h2d_channel_index.value(), network_index, nn_stream_config,
- intermediate_buffer.descriptors_in_frame(), intermediate_buffer.dma_address(), intermediate_buffer.depth(),
- intermediate_buffer.desc_page_size());
+ intermediate_buffer.get_host_buffer_info(), initial_credit_size);
}
static hailo_status fill_boundary_output_layer(CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
uint8_t **context_meta_data_head_pointer, ResourcesManager &resources_manager, uint8_t stream_index,
const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, uint32_t frame_credits_in_bytes,
ContextSwitchChannelsParsingInfo &channels_parsing_info, const std::string &layer_name, uint8_t network_index,
- const std::string &partial_network_name)
+ const std::string &network_name)
{
auto channel_index = resources_manager.get_available_channel_index(channels_parsing_info.D2H_channels_in_use,
ChannelInfo::Type::BOUNDARY, VdmaChannel::Direction::D2H, layer_name);
CHECK_EXPECTED_AS_STATUS(channel_info);
channel_info->get().set_pcie_stream_index(stream_index);
+
+ auto vdma_channel = resources_manager.create_boundary_vdma_channel(channel_index.value(), frame_credits_in_bytes,
+ network_name, layer_name, VdmaChannel::Direction::D2H);
+ CHECK_EXPECTED_AS_STATUS(vdma_channel);
+ auto page_size = vdma_channel.value()->get_page_size();
+
// Lock the channel for further use in this net_group
channels_parsing_info.D2H_channels_in_use.insert(channel_index.value());
- auto desc_sizes_pair = resources_manager.get_desc_buffer_sizes_for_boundary_channel(frame_credits_in_bytes,
- partial_network_name);
- CHECK_EXPECTED_AS_STATUS(desc_sizes_pair);
-
LOGGER__DEBUG("Boundary output stream: {} d2h_pcie_channel: {}.", stream_index, channel_index.value());
/* Update metadata */
auto status = HEF_METADATA__add_network_boundary_output_edge_layer(context_info,
context_meta_data_head_pointer, stream_index, channel_index.value(), network_index,
- nn_stream_config, frame_credits_in_bytes, desc_sizes_pair->first);
+ nn_stream_config, frame_credits_in_bytes, page_size);
CHECK_SUCCESS(status);
return HAILO_SUCCESS;
uint8_t **context_meta_data_head_pointer, ResourcesManager &resources_manager, uint8_t src_context,
uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, uint32_t frame_credits_in_bytes,
const ProtoHEFEdgeLayer *edge_layer_info, ContextSwitchChannelsParsingInfo &channels_parsing_info,
- std::set<uint8_t> &channels_to_unlock, uint8_t network_index, const std::string &partial_network_name)
+ std::set<uint8_t> &channels_to_unlock, uint8_t network_index, const std::string &network_name)
{
std::vector<uint8_t> connected_h2d_channels;
channels_to_unlock.insert(d2h_channel_index.value());
auto intermediate_buffer_exp = resources_manager.create_inter_context_buffer(frame_credits_in_bytes,
- stream_index, src_context, partial_network_name);
+ stream_index, src_context, network_name);
CHECK_EXPECTED_AS_STATUS(intermediate_buffer_exp);
auto &intermediate_buffer = intermediate_buffer_exp->get();
/* Update metadata */
auto status = HEF_METADATA__add_inter_context_output_edge_layer(context_info, context_meta_data_head_pointer,
- stream_index, d2h_channel_index.value(), network_index, nn_stream_config, frame_credits_in_bytes,
- intermediate_buffer.dma_address(), intermediate_buffer.descriptors_in_frame(),
- intermediate_buffer.desc_page_size(), intermediate_buffer.depth());
+ stream_index, d2h_channel_index.value(), network_index, nn_stream_config, intermediate_buffer.get_host_buffer_info());
CHECK_SUCCESS(status);
return HAILO_SUCCESS;
{
/* Find out if the connected layer has already been parsed */
uint8_t channel_index = 0;
+
+ CHECK(resources_manager.get_supported_features().padded_ddr_buffers, HAILO_INVALID_HEF,
+ "Failed opening non-compatible HEF that uses the following deprecated features: host-managed DDR buffers."
+ "Please re-compile the HEF using a newer Dataflow Compiler version (v3.11.0 or newer)");
+
if (HAILO_H2D_STREAM == direction) {
auto channel_index_expected = resources_manager.get_available_channel_index(channels_parsing_info.H2D_channels_in_use,
ChannelInfo::Type::DDR, VdmaChannel::Direction::H2D);
CHECK_EXPECTED_AS_STATUS(channel_index_expected);
channel_index = channel_index_expected.value();
channels_parsing_info.H2D_channels_in_use.insert(channel_index);
- /* If managed by the FW - allow reuse of the channel in between contexts */
- if (resources_manager.get_supported_features().padded_ddr_buffers) {
- channels_to_unlock.insert(channel_index);
- }
+ channels_to_unlock.insert(channel_index);
} else if (HAILO_D2H_STREAM == direction) {
auto channel_index_expected = resources_manager.get_available_channel_index(channels_parsing_info.D2H_channels_in_use,
ChannelInfo::Type::DDR, VdmaChannel::Direction::D2H);
CHECK_EXPECTED_AS_STATUS(channel_index_expected);
channel_index = channel_index_expected.value();
channels_parsing_info.D2H_channels_in_use.insert(channel_index);
- /* If managed by the FW - allow reuse of the channel in between contexts */
- if (resources_manager.get_supported_features().padded_ddr_buffers) {
- channels_to_unlock.insert(channel_index);
- }
+ channels_to_unlock.insert(channel_index);
} else {
LOGGER__ERROR("Invalid layer direction");
return HAILO_INVALID_ARGUMENT;
}
- auto fw_managed_channel = resources_manager.get_supported_features().padded_ddr_buffers;
for (auto &ddr_info : resources_manager.ddr_infos()) {
if (HAILO_H2D_STREAM == direction) {
/* we have the info already, just validate saved info, add ch_index, and return success! */
ddr_info.h2d_channel_index = channel_index;
LOGGER__DEBUG("DDR layer: input stream_index: {}, output stream_index: {}, h2d_pcie_channel {}, d2h_pcie_channel: {}.",
ddr_info.h2d_stream_index, ddr_info.d2h_stream_index, ddr_info.h2d_channel_index, ddr_info.d2h_channel_index);
+ const uint32_t initial_credit_size = get_initial_credit_size(edge_layer_proto);
return HEF_METADATA__add_ddr_buffer_input_edge_layer(context_switch_info,
context_meta_data_head_pointer, ddr_info.h2d_stream_index, ddr_info.h2d_channel_index, network_index,
- nn_stream_config, ddr_info.intermediate_buffer->dma_address(), ddr_info.intermediate_buffer->depth(), fw_managed_channel);
+ nn_stream_config, ddr_info.intermediate_buffer->dma_address(), ddr_info.intermediate_buffer->depth(),
+ initial_credit_size);
}
} else if (HAILO_D2H_STREAM == direction) {
/* we have the info already, just validate saved info, add ch_index, and return success! */
return HEF_METADATA__add_ddr_buffer_output_edge_layer(context_switch_info,
context_meta_data_head_pointer, ddr_info.d2h_stream_index, ddr_info.d2h_channel_index, network_index,
nn_stream_config, frame_credits_in_bytes, ddr_info.intermediate_buffer->dma_address(),
- static_cast<uint16_t>(ddr_info.intermediate_buffer->descs_count() - 1), ddr_info.intermediate_buffer->desc_page_size(),
- ddr_info.intermediate_buffer->depth(), fw_managed_channel);
+ ddr_info.intermediate_buffer->desc_page_size(), ddr_info.intermediate_buffer->depth(),
+ ddr_info.min_buffered_rows);
}
} else {
LOGGER__ERROR("Invalid layer direction");
local_info.intermediate_buffer = &ddr_buffer->get();
- if (resources_manager.get_supported_features().padded_ddr_buffers) {
- CHECK(0 == (DEFAULT_DESC_PAGE_SIZE % local_info.intermediate_buffer->desc_page_size()), HAILO_INTERNAL_FAILURE,
- "In padded DDR buffers, desc list page size must be dividor of {}", DEFAULT_DESC_PAGE_SIZE);
- CHECK(0 == (local_info.row_size % local_info.intermediate_buffer->desc_page_size()), HAILO_INTERNAL_FAILURE,
- "If HEF supports padded DDR buffers, row size must be a multiple of descriptor page size");
- local_info.descriptors_per_frame = (local_info.row_size / local_info.intermediate_buffer->desc_page_size()) *
- edge_layer_proto.layer_info().edge_layer_base().core_buffers_per_frame();
-
- auto programed_descs = ddr_buffer->get().program_ddr();
- CHECK_EXPECTED_AS_STATUS(programed_descs);
- local_info.initial_programed_descs = programed_descs.release();
- } else {
- LOGGER__WARNING("HEF from an old version detected. For optimal perfomance, please consider re-compile the HEF");
- auto programed_descs = ddr_buffer->get().program_host_managed_ddr(local_info.row_size,
- local_info.min_buffered_rows * DDR_THREADS_MIN_BUFFERED_ROWS_INITIAL_SCALE, 0);
- CHECK_EXPECTED_AS_STATUS(programed_descs);
- local_info.initial_programed_descs = programed_descs.release();
- local_info.descriptors_per_frame = 0; // unused for host controlled ddr buffering
- }
+ CHECK(0 == (DEFAULT_DESC_PAGE_SIZE % local_info.intermediate_buffer->desc_page_size()), HAILO_INTERNAL_FAILURE,
+ "In padded DDR buffers, desc list page size must be dividor of {}", DEFAULT_DESC_PAGE_SIZE);
+ CHECK(0 == (local_info.row_size % local_info.intermediate_buffer->desc_page_size()), HAILO_INTERNAL_FAILURE,
+ "If HEF supports padded DDR buffers, row size must be a multiple of descriptor page size");
+ local_info.descriptors_per_frame = (local_info.row_size / local_info.intermediate_buffer->desc_page_size()) *
+ edge_layer_proto.layer_info().edge_layer_base().core_buffers_per_frame();
+
+ auto programed_descs = ddr_buffer->get().program_ddr();
+ CHECK_EXPECTED_AS_STATUS(programed_descs);
+ local_info.initial_programed_descs = programed_descs.release();
local_info.desc_list_size_mask = static_cast<uint32_t>(local_info.intermediate_buffer->descs_count() - 1);
// Add layer to metadata
if (HAILO_H2D_STREAM == direction) {
+ const uint32_t initial_credit_size = get_initial_credit_size(edge_layer_proto);
auto status = HEF_METADATA__add_ddr_buffer_input_edge_layer(context_switch_info,
context_meta_data_head_pointer, local_info.h2d_stream_index, local_info.h2d_channel_index, network_index,
nn_stream_config, local_info.intermediate_buffer->dma_address(), local_info.intermediate_buffer->depth(),
- fw_managed_channel);
+ initial_credit_size);
CHECK_SUCCESS(status);
} else if (HAILO_D2H_STREAM == direction) {
auto status = HEF_METADATA__add_ddr_buffer_output_edge_layer(context_switch_info,
context_meta_data_head_pointer, local_info.d2h_stream_index, local_info.d2h_channel_index,
network_index, nn_stream_config, frame_credits_in_bytes, local_info.intermediate_buffer->dma_address(),
- static_cast<uint16_t>(local_info.intermediate_buffer->descs_count() - 1), local_info.intermediate_buffer->desc_page_size(),
- local_info.intermediate_buffer->depth(), fw_managed_channel);
+ local_info.intermediate_buffer->desc_page_size(), local_info.intermediate_buffer->depth(),
+ local_info.min_buffered_rows);
CHECK_SUCCESS(status);
} else {
LOGGER__ERROR("Invalid layer direction");
network_index, network_group_proto.networks_names_size());
return std::string(network_group_proto.networks_names(network_index));
} else {
- return HailoRTDefaults::get_partial_network_name();
+ auto partial_network_name = network_group_proto.network_group_metadata().network_group_name();
+ return partial_network_name;
}
}
+std::string HefUtils::get_network_name(const std::string &net_group_name, const std::string &partial_network_name)
+{
+ return net_group_name + HAILO_DEFAULT_NETWORK_NAME_QUALIFIER + partial_network_name;
+}
+
+std::string HefUtils::get_network_name(const ProtoHEFNetworkGroup &net_group, const std::string &partial_network_name)
+{
+ return HefUtils::get_network_name(net_group.network_group_metadata().network_group_name(), partial_network_name);
+}
+
static hailo_status parse_and_fill_h2d_layer_multi_context(
CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
uint8_t **context_meta_data_head_pointer, const ProtoHEFEdgeLayer &edge_layer_proto,
ContextSwitchChannelsParsingInfo &channels_parsing_info, ResourcesManager &resources_manager,
- uint8_t context_index, std::set<uint8_t> &channels_to_unlock)
+ uint8_t context_index, std::set<uint8_t> &channels_to_unlock, const std::string &network_name,
+ uint8_t network_index)
{
uint8_t stream_index = 0;
uint32_t frame_credits_in_bytes = 0;
edge_layer_proto.context_switch_info().edge_connection_type());
CHECK_EXPECTED_AS_STATUS(nn_stream_config, "Failed parse nn stream config");
auto layer_name = edge_layer_proto.layer_info().name();
- auto support_multi_networks = resources_manager.get_supported_features().multi_network_support;
- auto network_index = static_cast<uint8_t>((support_multi_networks) ? edge_layer_proto.network_index() : 0);
/* credits work on periph bytes */
frame_credits_in_bytes = (nn_stream_config->periph_bytes_per_buffer * nn_stream_config->core_buffers_per_frame);
switch (edge_layer_proto.context_switch_info().edge_connection_type()) {
case ProtoHEFEdgeConnectionType::PROTO__EDGE_CONNECTION_TYPE__BOUNDARY:
return fill_boundary_input_layer(context_info, context_meta_data_head_pointer, stream_index,
- *nn_stream_config, channels_parsing_info, resources_manager, layer_name, network_index);
+ edge_layer_proto, *nn_stream_config, channels_parsing_info, resources_manager, layer_name,
+ network_name, network_index, frame_credits_in_bytes);
case ProtoHEFEdgeConnectionType::PROTO__EDGE_CONNECTION_TYPE__INTERMEDIATE:
return fill_inter_context_input_layer(context_info, context_meta_data_head_pointer, resources_manager,
}
}
-static hailo_status parse_and_fill_d2h_layer_multi_context(ProtoHEFNetworkGroupPtr network_group_proto,
- CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
- uint8_t **context_meta_data_head_pointer, const ProtoHEFEdgeLayer &edge_layer_proto,
- ContextSwitchChannelsParsingInfo &channels_parsing_info, ResourcesManager &resources_manager,
- uint8_t context_index, std::set<uint8_t> &channels_to_unlock)
+static hailo_status parse_and_fill_d2h_layer_multi_context(
+ CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
+ uint8_t **context_meta_data_head_pointer, const ProtoHEFEdgeLayer &edge_layer_proto,
+ ContextSwitchChannelsParsingInfo &channels_parsing_info, ResourcesManager &resources_manager,
+ uint8_t context_index, std::set<uint8_t> &channels_to_unlock, const std::string &network_name,
+ uint8_t network_index)
{
uint8_t stream_index = 0;
uint32_t frame_credits_in_bytes = 0;
return HAILO_INVALID_HEF;
}
- auto support_multi_networks = resources_manager.get_supported_features().multi_network_support;
- auto network_index = static_cast<uint8_t>((support_multi_networks) ? edge_layer_proto.network_index() : 0);
- auto partial_network_name = HefUtils::get_partial_network_name_by_index(*network_group_proto, network_index,
- resources_manager.get_supported_features());
- CHECK_EXPECTED_AS_STATUS(partial_network_name);
-
switch (edge_layer_proto.context_switch_info().edge_connection_type()) {
case ProtoHEFEdgeConnectionType::PROTO__EDGE_CONNECTION_TYPE__BOUNDARY:
return fill_boundary_output_layer(context_info, context_meta_data_head_pointer, resources_manager,
stream_index, nn_stream_config, frame_credits_in_bytes, channels_parsing_info, layer_name,
- network_index, partial_network_name.value());
+ network_index, network_name);
case ProtoHEFEdgeConnectionType::PROTO__EDGE_CONNECTION_TYPE__INTERMEDIATE:
CHECK(!is_mux, HAILO_INVALID_HEF, "Inter-context layer can't be mux.");
return fill_inter_context_output_layer(context_info, context_meta_data_head_pointer, resources_manager,
context_index, stream_index, nn_stream_config, frame_credits_in_bytes,
- &edge_layer_proto, channels_parsing_info, channels_to_unlock, network_index, partial_network_name.value());
+ &edge_layer_proto, channels_parsing_info, channels_to_unlock, network_index, network_name);
case ProtoHEFEdgeConnectionType::PROTO__EDGE_CONNECTION_TYPE__DDR:
return fill_ddr_layer_multi_context(context_info, context_meta_data_head_pointer, resources_manager, context_index,
}
}
-static hailo_status parse_and_fill_layers_mapping_multi_context(ProtoHEFNetworkGroupPtr network_group_proto,
+static hailo_status fill_ddr_buffers_info(CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
+ uint8_t **context_meta_data_head_pointer, ResourcesManager &resources_manager, uint8_t context_index)
+{
+ const CONTROL_PROTOCOL__TRIGGER_t none_trigger = HEF_METADATA__build_none_trigger();
+ bool found_ddr_pair_for_context = false;
+ // See: HRT-5373
+ static const bool NOT_REPEATED = false;
+
+ for (auto& ddr_info : resources_manager.ddr_infos()) {
+ if (context_index == ddr_info.context_index) {
+ /* Any action must have a trigger */
+ auto status = HEF_METADATA__add_trigger_to_trigger_group(context_info, context_meta_data_head_pointer,
+ &none_trigger);
+ CHECK_SUCCESS(status, "failed to add NONE trigger before ddr buffer pair infos");
+ /* Add ddr pair info action */
+ status = HEF_METADATA__add_ddr_pair_info(context_info, context_meta_data_head_pointer,
+ ddr_info.h2d_channel_index, ddr_info.d2h_channel_index, ddr_info.descriptors_per_frame,
+ ddr_info.initial_programed_descs, NOT_REPEATED);
+ CHECK_SUCCESS(status,"failed to add ddr pair info");
+ found_ddr_pair_for_context = true;
+ }
+ }
+
+ if (found_ddr_pair_for_context) {
+ /* No need to add NONE trigger. This action can be inside the last none trigger of the last DDR pair */
+ auto status = HEF_METADATA__add_ddr_buffering_start(context_info, context_meta_data_head_pointer, NOT_REPEATED);
+ CHECK_SUCCESS(status,"failed to add ddr buffer start action");
+ }
+
+ return HAILO_SUCCESS;
+}
+
+static hailo_status parse_and_fill_edge_layers_mapping(ProtoHEFNetworkGroupPtr network_group_proto,
CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
uint8_t **context_meta_data_head_pointer, const ProtoHEFContextMetadata *context_metadata,
ContextSwitchChannelsParsingInfo &channels_parsing_info, ResourcesManager &resources_manager, uint8_t context_index)
// We use those sets to unlock resources at the end of each context parsing to prevent reuse within the same context
std::set<uint8_t> channels_to_unlock = {};
- CHECK(0 < context_metadata->edge_layers_size(), HAILO_INVALID_HEF, "No edge layers in this context");
+ const auto number_of_edge_layers = context_metadata->edge_layers_size();
+ CHECK(0 < number_of_edge_layers, HAILO_INVALID_HEF, "No edge layers in this context");
+ CHECK(IS_FIT_IN_UINT8(number_of_edge_layers), HAILO_INVALID_HEF,
+ "Failed to parse HEF. Invalid edge_layers_size: {}.", number_of_edge_layers);
for (const auto &edge_layer_proto : context_metadata->edge_layers()) {
+ auto support_multi_networks = resources_manager.get_supported_features().multi_network_support;
+ auto network_index = static_cast<uint8_t>((support_multi_networks) ? edge_layer_proto.network_index() : 0);
+ auto partial_network_name = HefUtils::get_partial_network_name_by_index(*network_group_proto, network_index,
+ resources_manager.get_supported_features());
+ CHECK_EXPECTED_AS_STATUS(partial_network_name);
+ auto network_name = HefUtils::get_network_name(*network_group_proto, partial_network_name.value());
+
if (ProtoHEFEdgeLayerDirection::PROTO__EDGE_LAYER_DIRECTION__HOST_TO_DEVICE == edge_layer_proto.direction()) {
status = parse_and_fill_h2d_layer_multi_context(context_info, context_meta_data_head_pointer,
- edge_layer_proto, channels_parsing_info, resources_manager, context_index, channels_to_unlock);
+ edge_layer_proto, channels_parsing_info, resources_manager, context_index, channels_to_unlock,
+ network_name, network_index);
CHECK_SUCCESS(status);
} else if (ProtoHEFEdgeLayerDirection::PROTO__EDGE_LAYER_DIRECTION__DEVICE_TO_HOST == edge_layer_proto.direction()) {
- status = parse_and_fill_d2h_layer_multi_context(network_group_proto, context_info, context_meta_data_head_pointer,
- edge_layer_proto, channels_parsing_info, resources_manager, context_index, channels_to_unlock);
+ status = parse_and_fill_d2h_layer_multi_context(context_info, context_meta_data_head_pointer,
+ edge_layer_proto, channels_parsing_info, resources_manager, context_index, channels_to_unlock,
+ network_name, network_index);
CHECK_SUCCESS(status);
} else {
LOGGER__ERROR("Invalid argument: stream_direction");
}
}
- return HAILO_SUCCESS;
-}
-
-static hailo_status fill_ddr_buffers_info(CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
- uint8_t **context_meta_data_head_pointer, ResourcesManager &resources_manager, uint8_t context_index)
-{
- const CONTROL_PROTOCOL__TRIGGER_t none_trigger = HEF_METADATA__build_none_trigger();
- bool found_ddr_pair_for_context = false;
- // See: HRT-5373
- static const bool NOT_REPEATED = false;
-
- for (auto& ddr_info : resources_manager.ddr_infos()) {
- if (context_index == ddr_info.context_index) {
- /* Any action must have a trigger */
- auto status = HEF_METADATA__add_trigger_to_trigger_group(context_info, context_meta_data_head_pointer,
- &none_trigger);
- CHECK_SUCCESS(status, "failed to add NONE trigger before ddr buffer pair infos");
- /* Add ddr pair info action */
- status = HEF_METADATA__add_ddr_pair_info(context_info, context_meta_data_head_pointer,
- ddr_info.h2d_channel_index, ddr_info.d2h_channel_index, ddr_info.descriptors_per_frame,
- ddr_info.initial_programed_descs, NOT_REPEATED);
- CHECK_SUCCESS(status,"failed to add ddr pair info");
- found_ddr_pair_for_context = true;
- }
- }
-
- if (found_ddr_pair_for_context) {
- /* No need to add NONE trigger. This action can be inside the last none trigger of the last DDR pair */
- auto status = HEF_METADATA__add_ddr_buffering_start(context_info, context_meta_data_head_pointer, NOT_REPEATED);
- CHECK_SUCCESS(status,"failed to add ddr buffer start action");
- }
+ status = fill_ddr_buffers_info(context_info, context_meta_data_head_pointer, resources_manager, context_index);
+ CHECK_SUCCESS(status);
return HAILO_SUCCESS;
}
return result;
}
-static std::set<uint32_t> get_end_indexes_of_write_ccw_actions(
+static std::set<uint32_t> get_end_indexes_of_action_type(
const std::vector<ContextSwitchConfigActionPtr> &actions,
- const std::vector<std::pair<uint32_t, uint32_t>> &repeated_indexes)
+ const std::vector<std::pair<uint32_t, uint32_t>> &repeated_indexes,
+ const ContextSwitchConfigAction::Type &required_action_type)
{
std::set<uint32_t> result;
for (const auto &index_pair : repeated_indexes) {
const auto curr_action_type = actions[index_pair.first]->get_type();
- if (ContextSwitchConfigAction::Type::WriteDataCcw != curr_action_type) {
+ if (required_action_type != curr_action_type) {
continue;
}
}
static hailo_status proccess_write_ccw_action(const ContextSwitchConfigActionPtr &configuration_action,
- std::vector<ConfigResources> &config_resources, std::set<uint8_t> &pending_cfg_ch_buffer,
+ std::vector<ConfigBuffer> &config_resources, std::set<uint8_t> &pending_cfg_ch_buffer,
std::vector<uint16_t> &total_ccw_bursts, const std::set<uint32_t> &end_indexes_of_write_ccw_actions,
const uint32_t &action_index, const bool support_pre_fetch,
std::vector<ContextSwitchConfigActionPtr> &processed_configuration_actions)
/* Add the last CCW write into the buffer */
processed_configuration_actions.emplace_back(configuration_action);
- /* Build descriptor list for this buffer */
- auto create_desc_action = CreateConfigDescAndFetchAction::create(config_resources, pending_cfg_ch_buffer,
- total_ccw_bursts, support_pre_fetch);
- CHECK_EXPECTED_AS_STATUS(create_desc_action);
- processed_configuration_actions.emplace_back(create_desc_action.release());
+ CHECK(total_ccw_bursts.size() == config_resources.size(), HAILO_INTERNAL_FAILURE, "Invalid cfg channels count");
+ for (const auto cfg_channel : pending_cfg_ch_buffer) {
+ CHECK(cfg_channel < config_resources.size(), HAILO_INTERNAL_FAILURE, "Invalid cfg channel index");
+
+ auto fetch_config_action = support_pre_fetch ?
+ AddCcwBurstAction::create(cfg_channel, total_ccw_bursts[cfg_channel]) :
+ CreateConfigDescAndFetchAction::create(cfg_channel, config_resources[cfg_channel]);
+ CHECK_EXPECTED_AS_STATUS(fetch_config_action);
+ processed_configuration_actions.emplace_back(fetch_config_action.release());
+ }
/* Cleanups */
pending_cfg_ch_buffer.clear();
return HAILO_SUCCESS;
}
+static hailo_status proccess_trigger_new_data_input_action(const ContextSwitchConfigActionPtr &configuration_action,
+ const std::set<uint32_t> &end_indexes_of_trigger_new_data_input_actions,
+ const uint32_t &action_index, std::vector<ContextSwitchConfigActionPtr> &processed_configuration_actions)
+{
+ // At the end of a consecutive group of TriggerNewDataFromDataInput actions, we can trigger the BurstCreditsTask
+ // in the FW, via StartBurstCreditsTaskAction.
+ processed_configuration_actions.emplace_back(configuration_action);
+ if (contains(end_indexes_of_trigger_new_data_input_actions, action_index)) {
+ auto start_burst_credits_task_action = StartBurstCreditsTaskAction::create();
+ CHECK_EXPECTED_AS_STATUS(start_burst_credits_task_action);
+ processed_configuration_actions.emplace_back(start_burst_credits_task_action.release());
+ }
+
+ return HAILO_SUCCESS;
+}
// Adds context switch configuration actions that don't appear in the HEF:
// * If groups of consecutive actions can be "merged" as repeated actions (saving room the FW's
// action list) a RepeatedHeaderAction is placed before the relevant actions.
// See also: CONTROL_PROTOCOL__REPEATED_ACTION_t's documnetion in control_protocol.h.
// * At the end of each consecutive group of WriteDataCcwAction, a CreateConfigDescAndFetchAction is added.
+// * At the end of each consecutive group of TriggerNewDataFromDataInput, a StartBurstCreditsTaskAction is added.
static Expected<std::vector<ContextSwitchConfigActionPtr>> process_configuration_actions(
std::vector<ContextSwitchConfigActionPtr> &input_configuration_actions,
- std::vector<ConfigResources> &config_resources, const bool support_pre_fetch)
+ std::vector<ConfigBuffer> &config_resources, const bool support_pre_fetch)
{
std::vector<ContextSwitchConfigActionPtr> processed_configuration_actions;
std::vector<uint16_t> total_ccw_bursts(config_resources.size(), 0);
const auto repeated_indexes = get_repreated_actions_boundary_indices(input_configuration_actions);
- const auto start_indexes_of_repeated_actions = get_start_indexes_of_repeated_actions(input_configuration_actions, repeated_indexes);
- const auto end_indexes_of_write_ccw_actions = get_end_indexes_of_write_ccw_actions(input_configuration_actions, repeated_indexes);
+ const auto start_indexes_of_repeated_actions = get_start_indexes_of_repeated_actions(
+ input_configuration_actions, repeated_indexes);
+ const auto end_indexes_of_write_ccws = get_end_indexes_of_action_type(input_configuration_actions,
+ repeated_indexes, ContextSwitchConfigAction::Type::WriteDataCcw);
+ const auto end_indexes_of_trigger_new_data_from_inputs = get_end_indexes_of_action_type(
+ input_configuration_actions, repeated_indexes, ContextSwitchConfigAction::Type::TriggerNewDataFromDataInput);
for (uint32_t action_index = 0; action_index < input_configuration_actions.size(); action_index++) {
// A group of actions can be "merged" as repeated actions.
// Hence we add a RepeatedHeaderAction and mark all the actions in this group as "reapted"
// Add the current action
const auto &configuration_action = input_configuration_actions[action_index];
-
if (ContextSwitchConfigAction::Type::WriteDataCcw == configuration_action->get_type()) {
auto status = proccess_write_ccw_action(configuration_action, config_resources, pending_cfg_ch_buffer,
- total_ccw_bursts, end_indexes_of_write_ccw_actions, action_index,
- support_pre_fetch, processed_configuration_actions);
+ total_ccw_bursts, end_indexes_of_write_ccws, action_index, support_pre_fetch, processed_configuration_actions);
+ CHECK_SUCCESS_AS_EXPECTED(status);
+ } else if (ContextSwitchConfigAction::Type::TriggerNewDataFromDataInput == configuration_action->get_type()) {
+ auto status = proccess_trigger_new_data_input_action(configuration_action, end_indexes_of_trigger_new_data_from_inputs,
+ action_index, processed_configuration_actions);
CHECK_SUCCESS_AS_EXPECTED(status);
} else {
// Add the current action
}
static hailo_status parse_actions_in_operation(const ProtoHEFOperation &operation,
- Device &device, const ProtoHEFHwArch &hw_arch, std::vector<ConfigResources> &config_resources,
+ Device &device, const ProtoHEFHwArch &hw_arch, std::vector<ConfigBuffer> &config_resources,
const ResourcesManager &resources_manager, ProtoHEFNetworkGroupPtr network_group_proto,
CONTROL_PROTOCOL__context_switch_context_info_t &context_info, uint8_t **context_meta_data_head_pointer)
{
uint8_t *context_meta_data_head_pointer = context_info.context_network_data;
// Add edge layers mapping
- status = parse_and_fill_layers_mapping_multi_context(network_group_proto, &context_info, &context_meta_data_head_pointer,
+ status = parse_and_fill_edge_layers_mapping(network_group_proto, &context_info, &context_meta_data_head_pointer,
&proto_context.metadata(), channels_parsing_info, resources_manager, context_index);
CHECK_SUCCESS(status);
- auto number_of_edge_layers = proto_context.metadata().edge_layers_size();
- CHECK(IS_FIT_IN_UINT8(number_of_edge_layers), HAILO_INVALID_HEF,
- "Failed to parse HEF. Invalid edge_layers_size: {}.", number_of_edge_layers);
-
- // For the case of DDR buffers in FW - add DDR info after parsing all edge layers and before parsing all other actions
- if (resources_manager.get_supported_features().padded_ddr_buffers) {
- status = fill_ddr_buffers_info(&context_info, &context_meta_data_head_pointer, resources_manager, context_index);
- CHECK_SUCCESS(status);
- }
-
CHECK(IS_FIT_IN_UINT8(proto_context.operations_size()), HAILO_INVALID_HEF,
"Failed to parse HEF. Invalid operations_count: {}.", proto_context.operations_size());
context_info.context_stream_remap_data.should_use_stream_remap = static_cast<uint8_t>(proto_context.metadata().shmiglue_info().should_use_shmiglue());
- /* Parse context */
+ // Parse context
for (const auto &operation : proto_context.operations()) {
const auto operation_trigger = ContextSwitchTrigger::create(operation.trigger());
CHECK_EXPECTED_AS_STATUS(operation_trigger);
static hailo_status fill_preliminary_config_recepies_for_multi_context(const ProtoHEFHwArch &hw_arch,
CONTROL_PROTOCOL__context_switch_context_info_t &context_info, ResourcesManager &resources_manager,
- ProtoHEFNetworkGroupPtr network_group_proto, const ProtoHEFPreliminaryConfig &proto_preliminary_config, Device &device)
+ ContextSwitchChannelsParsingInfo &channels_parsing_info, ProtoHEFNetworkGroupPtr network_group_proto,
+ const ProtoHEFPreliminaryConfig &proto_preliminary_config, Device &device)
{
uint8_t *context_meta_data_head_pointer = context_info.context_network_data;
CHECK(IS_FIT_IN_UINT8(proto_preliminary_config.operation_size()), HAILO_INVALID_HEF,
"Failed to parse HEF. Invalid operations_count: {}.", proto_preliminary_config.operation_size());
- /* Parse preliminary config */
+ if (resources_manager.get_supported_features().preliminary_run_asap) {
+ // Add edge layers mapping (only preliminary_run_asap networks have edge layers in the preliminary context)
+ static const auto PRELIMINARY_CONTEXT_INDEX = 0;
+ auto status = parse_and_fill_edge_layers_mapping(network_group_proto, &context_info, &context_meta_data_head_pointer,
+ &(network_group_proto->contexts(PRELIMINARY_CONTEXT_INDEX).metadata()), channels_parsing_info, resources_manager,
+ PRELIMINARY_CONTEXT_INDEX);
+ CHECK_SUCCESS(status);
+ }
+
+ // Parse preliminary config
for (const auto &operation_proto : proto_preliminary_config.operation()) {
const auto operation_trigger = ContextSwitchTrigger::create(operation_proto.trigger());
CHECK_EXPECTED_AS_STATUS(operation_trigger);
CHECK_SUCCESS(status);
}
- // update context_network_data_length per context, and preliminary_context_descriptors count in main header
+ // Update context_network_data_length per context, and preliminary_context_descriptors count in main header
context_info.context_network_data_length =
static_cast<uint32_t>(context_meta_data_head_pointer - context_info.context_network_data);
auto preliminary_context = resources_manager->add_new_context();
CHECK_EXPECTED(preliminary_context);
+ // TODO: Support sharing of ContextSwitchChannelsParsingInfo between fill_preliminary_config_recepies_for_multi_context
+ // and fill_context_recepies_for_multi_context (HRT-6683).
+ // When running in preliminary_run_asap mode the channels used by the first dynamic context and by the preliminary
+ // context are the same channels. We need to add the sane edge_layers for both contexts (look for calls to
+ // hef_metadata__add_edge_layer_header) so that the needed actions will be added to the action list. However,
+ // due to the logic in ResourceManager::get_available_channel_index's blacklist channels that should be the same
+ // will get different indexes. Need to refactor the logic of that function and the entire channel index allocation logic.
+ ContextSwitchChannelsParsingInfo channels_parsing_info_preliminary{};
auto status = fill_preliminary_config_recepies_for_multi_context(hw_arch, preliminary_context.value().get(),
- resources_manager.value(), network_group_proto, network_group_proto->preliminary_config(), device);
+ resources_manager.value(), channels_parsing_info_preliminary, network_group_proto, network_group_proto->preliminary_config(),
+ device);
CHECK_SUCCESS_AS_EXPECTED(status);
resources_manager->update_preliminary_config_buffer_info();
- ContextSwitchChannelsParsingInfo channels_parsing_info = {};
-
+ ContextSwitchChannelsParsingInfo channels_parsing_info_dynamic{};
for (uint8_t context_index = 0; context_index < network_group_proto->contexts_size(); ++context_index) {
auto new_context = resources_manager->add_new_context();
CHECK_EXPECTED(new_context);
status = fill_context_recepies_for_multi_context(network_group_proto, hw_arch, new_context.value().get(), resources_manager.value(),
- context_index, network_group_proto->contexts(context_index), device, channels_parsing_info);
+ context_index, network_group_proto->contexts(context_index), device, channels_parsing_info_dynamic);
CHECK_SUCCESS_AS_EXPECTED(status);
}
resources_manager->update_dynamic_contexts_buffer_info();
- status = resources_manager->create_vdma_channels();
+ status = resources_manager->create_internal_vdma_channels();
CHECK_SUCCESS_AS_EXPECTED(status);
auto resources_manager_ptr = make_shared_nothrow<ResourcesManager>(resources_manager.release());
}
Expected<ContextSwitchConfigActionPtr> ContextSwitchConfigAction::create(const ProtoHEFAction &proto_action, Device &device,
- std::vector<ConfigResources> &config, const ResourcesManager &resources_manager, const ProtoHEFNetworkGroup &net_group,
+ std::vector<ConfigBuffer> &config, const ResourcesManager &resources_manager, const ProtoHEFNetworkGroup &net_group,
bool support_pre_fetch)
{
switch (proto_action.action_case()) {
}
Expected<ContextSwitchConfigActionPtr> WriteDataCcwAction::create(const ProtoHEFAction& proto_action,
- std::vector<ConfigResources> &config, bool support_pre_fetch)
+ std::vector<ConfigBuffer> &config, bool support_pre_fetch)
{
// Add buffer to cfg_ch buffer without making descriptors (saving offset as the total data so far)
CHECK_AS_EXPECTED(proto_action.write_data_ccw().cfg_channel_index() < config.size(), HAILO_INVALID_HEF,
CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.write_data_ccw().cfg_channel_index()), HAILO_INVALID_HEF,
"Invalid cfg channel index");
- auto result = ContextSwitchConfigActionPtr(new (std::nothrow) WriteDataCcwAction(proto_action, config,
- support_pre_fetch));
+ auto result = ContextSwitchConfigActionPtr(new (std::nothrow) WriteDataCcwAction(proto_action,
+ config[proto_action.write_data_ccw().cfg_channel_index()], support_pre_fetch));
CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY);
return result;
}
-WriteDataCcwAction::WriteDataCcwAction(const ProtoHEFAction& proto_action, std::vector<ConfigResources> &config,
+WriteDataCcwAction::WriteDataCcwAction(const ProtoHEFAction& proto_action, ConfigBuffer &config,
bool support_pre_fetch) :
ContextSwitchConfigAction(Type::WriteDataCcw, proto_action),
m_config(config),
m_support_pre_fetch(support_pre_fetch)
{}
-bool WriteDataCcwAction::should_pad_with_nops()
+bool WriteDataCcwAction::is_last_ccw_write()
{
- if (!m_support_pre_fetch) {
- return false;
- }
-
auto write_size = m_proto_action.write_data_ccw().data().length();
- auto cfg_channel = m_proto_action.write_data_ccw().cfg_channel_index();
/* If last operation in context - Add nops to fill the buffer */
- if ((write_size + m_config[cfg_channel].get_current_buffer_size()) != m_config[cfg_channel].get_total_cfg_size()) {
+ if ((write_size + m_config.get_current_buffer_size()) != m_config.get_total_cfg_size()) {
return false;
}
return true;
}
-hailo_status WriteDataCcwAction::pad_with_nops(uint8_t cfg_channel_index)
+hailo_status WriteDataCcwAction::pad_with_nops()
{
- auto page_size = m_config[cfg_channel_index].get_page_size();
- auto buffer_size = m_config[cfg_channel_index].get_total_cfg_size();
+ auto page_size = m_config.desc_page_size();
+ auto buffer_size = m_config.get_total_cfg_size();
auto buffer_residue = buffer_size % page_size;
if (0 != buffer_residue % CCW_HEADER_SIZE) {
LOGGER__ERROR("CFG channel buffer size must be a multiple of CCW header size ({})", CCW_HEADER_SIZE);
CCW of all zeros (64’h0) should be treated as NOP – ignore CCW and expect CCW in next 64b word.
When CSM recognize it is a NOP it pops it from the channel FIFO without forward any address/data/command,
does not contribute to CRC calculations but return credits to the peripheral as usual. */
- m_config[cfg_channel_index].write(reinterpret_cast<const void *>(&CCW_NOP), sizeof(CCW_NOP));
+ m_config.write(reinterpret_cast<const void *>(&CCW_NOP), sizeof(CCW_NOP));
}
return HAILO_SUCCESS;
hailo_status WriteDataCcwAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *, uint8_t **)
{
- if (should_pad_with_nops()) {
- auto status = pad_with_nops(static_cast<uint8_t>(m_proto_action.write_data_ccw().cfg_channel_index()));
+ const bool is_last_write = is_last_ccw_write();
+ if (m_support_pre_fetch && is_last_write) {
+ auto status = pad_with_nops();
CHECK_SUCCESS(status);
}
- return m_config[m_proto_action.write_data_ccw().cfg_channel_index()].write(
- m_proto_action.write_data_ccw().data().data(), m_proto_action.write_data_ccw().data().length());
+ auto status = m_config.write(m_proto_action.write_data_ccw().data().data(),
+ m_proto_action.write_data_ccw().data().length());
+ CHECK_SUCCESS(status);
+
+ if (m_support_pre_fetch && is_last_write) {
+ auto desc_count = m_config.program_descriptors();
+ CHECK_EXPECTED_AS_STATUS(desc_count);
+ }
+
+ return HAILO_SUCCESS;
}
bool WriteDataCcwAction::supports_repeated_block() const
return false;
}
-Expected<ContextSwitchConfigActionPtr> CreateConfigDescAndFetchAction::create(
- std::vector<ConfigResources> &config_resources, const std::set<uint8_t> &pending_cfg_ch_buffer,
- const std::vector<uint16_t> &ccw_bursts, bool support_pre_fetch)
+Expected<ContextSwitchConfigActionPtr> AddCcwBurstAction::create(uint8_t channel_index, uint16_t ccw_bursts)
{
- CHECK_AS_EXPECTED(pending_cfg_ch_buffer.size() > 0, HAILO_INTERNAL_FAILURE,
- "Expected 1 or more pending_cfg_ch_buffer, however 0 were found");
- CHECK_AS_EXPECTED(ccw_bursts.size() == config_resources.size(), HAILO_INTERNAL_FAILURE,
- "CCW burst vector size must match the config resources size");
-
- auto result = ContextSwitchConfigActionPtr(new (std::nothrow) CreateConfigDescAndFetchAction(config_resources,
- pending_cfg_ch_buffer, ccw_bursts, support_pre_fetch));
+ auto result = ContextSwitchConfigActionPtr(new (std::nothrow) AddCcwBurstAction(channel_index, ccw_bursts));
CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY);
return result;
}
-CreateConfigDescAndFetchAction::CreateConfigDescAndFetchAction(std::vector<ConfigResources> &config, const std::set<uint8_t> &pending_cfg_ch_buffer,
- const std::vector<uint16_t> &ccw_bursts, bool support_pre_fetch) :
- ContextSwitchConfigAction(Type::CreateDescForCcw),
- m_config(config),
- m_pending_cfg_ch_buffer(pending_cfg_ch_buffer),
- m_ccw_bursts(ccw_bursts),
- m_support_pre_fetch(support_pre_fetch)
+AddCcwBurstAction::AddCcwBurstAction(uint8_t channel_index, uint16_t ccw_bursts) :
+ ContextSwitchConfigAction(Type::AddCcwBurst),
+ m_channel_index(channel_index),
+ m_ccw_bursts(ccw_bursts)
{}
-hailo_status CreateConfigDescAndFetchAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
+hailo_status AddCcwBurstAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
uint8_t **context_meta_data_head_pointer)
{
- for (auto cfg_channel_index : m_pending_cfg_ch_buffer) {
+ return HEF_METADATA__add_ccw_bursts_action(context_info, context_meta_data_head_pointer,
+ m_ccw_bursts, m_channel_index, m_is_in_repeated_block);
+}
- CHECK(cfg_channel_index < m_ccw_bursts.size(), HAILO_INTERNAL_FAILURE,
- "cfg_channel_index vector size must then m_ccw_burst size");
+bool AddCcwBurstAction::supports_repeated_block() const
+{
+ return false;
+}
- const auto desc_count = m_config[cfg_channel_index].program_descriptors();
- CHECK_EXPECTED_AS_STATUS(desc_count);
+Expected<ContextSwitchConfigActionPtr> CreateConfigDescAndFetchAction::create(uint8_t channel_index, ConfigBuffer &config_buffer)
+{
+ auto result = ContextSwitchConfigActionPtr(new (std::nothrow) CreateConfigDescAndFetchAction(channel_index, config_buffer));
+ CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY);
+ return result;
+}
- if (m_support_pre_fetch) {
- auto status = HEF_METADATA__add_ccw_bursts_action(context_info, context_meta_data_head_pointer,
- static_cast<uint16_t>(m_ccw_bursts[cfg_channel_index]), cfg_channel_index, m_is_in_repeated_block);
- CHECK_SUCCESS(status);
- } else {
- auto status = HEF_METADATA__add_read_vdma_action(context_info, context_meta_data_head_pointer, desc_count.value(),
- cfg_channel_index, m_is_in_repeated_block);
- CHECK_SUCCESS(status);
- }
- }
+CreateConfigDescAndFetchAction::CreateConfigDescAndFetchAction(uint8_t channel_index, ConfigBuffer &config_buffer) :
+ ContextSwitchConfigAction(Type::CreateDescForCcw),
+ m_channel_index(channel_index),
+ m_config_buffer(config_buffer)
+{}
- return HAILO_SUCCESS;
+hailo_status CreateConfigDescAndFetchAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
+ uint8_t **context_meta_data_head_pointer)
+{
+ const auto desc_count = m_config_buffer.program_descriptors();
+ CHECK_EXPECTED_AS_STATUS(desc_count);
+
+ CHECK(IS_FIT_IN_UINT16(desc_count.value()), HAILO_INVALID_OPERATION,
+ "On cfg with continuous mode, max descriptors size must fit in uint16_t");
+ return HEF_METADATA__add_read_vdma_action(context_info, context_meta_data_head_pointer,
+ static_cast<uint16_t>(desc_count.value()), m_channel_index, m_is_in_repeated_block);
}
bool CreateConfigDescAndFetchAction::supports_repeated_block() const
return false;
}
+Expected<ContextSwitchConfigActionPtr> StartBurstCreditsTaskAction::create()
+{
+ auto result = ContextSwitchConfigActionPtr(new (std::nothrow) StartBurstCreditsTaskAction());
+ CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY);
+ return result;
+}
+
+StartBurstCreditsTaskAction::StartBurstCreditsTaskAction() :
+ ContextSwitchConfigAction(Type::StartBurstCreditsTask)
+{}
+
+hailo_status StartBurstCreditsTaskAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
+ uint8_t **context_meta_data_head_pointer)
+{
+ return HEF_METADATA__burst_credits_task_start(context_info, context_meta_data_head_pointer,
+ m_is_in_repeated_block);
+}
+
+bool StartBurstCreditsTaskAction::supports_repeated_block() const
+{
+ // We don't support repeated blocks for this action, since only one is added per group of consecutive
+ // TriggerNewDataFromDataInput actions.
+ return false;
+}
+
Expected<ContextSwitchConfigActionPtr> RepeatedHeaderAction::create(
CONTROL_PROTOCOL__ACTION_TYPE_t sub_action_type, uint8_t num_actions)
{
auto partial_network_name = HefUtils::get_partial_network_name_by_index(net_group, network_index,
resources_manager.get_supported_features());
CHECK_EXPECTED(partial_network_name);
- auto batch_size = resources_manager.get_network_batch_size_from_partial_name(partial_network_name.value());
- CHECK_EXPECTED(batch_size);
+ auto network_name = HefUtils::get_network_name(net_group, partial_network_name.value());
+
+ auto batch_size = resources_manager.get_network_batch_size(network_name);
+ CHECK_EXPECTED(batch_size);
const auto kernel_done_address = static_cast<uint16_t>(proto_action.enable_lcu().lcu_kernel_done_address());
const auto kernel_done_count = static_cast<uint32_t>(proto_action.enable_lcu().lcu_kernel_done_count());
const auto is_default = (CONTEXT_SWITCH_DEFS__ENABLE_LCU_DEFAULT_KERNEL_ADDRESS == kernel_done_address) &&
- (CONTEXT_SWITCH_DEFS__ENABLE_LCU_DEFAULT_KERNEL_COUNT == kernel_done_count) &&
- (CONTEXT_SWITCH_DEFS__ENABLE_LCU_DEFAULT_BATCH_SIZE == batch_size.value());
+ (CONTEXT_SWITCH_DEFS__ENABLE_LCU_DEFAULT_KERNEL_COUNT == kernel_done_count);
auto result = ContextSwitchConfigActionPtr(new (std::nothrow) EnableLcuAction(proto_action, is_default, network_index));
CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY);
const auto lcu_index = static_cast<uint8_t>(m_proto_action.enable_lcu().lcu_index());
if (m_is_default) {
return HEF_METADATA__add_enable_lcu_default_action(context_info, context_meta_data_head_pointer,
- cluster_index, lcu_index, m_is_in_repeated_block);
+ cluster_index, lcu_index, m_network_index, m_is_in_repeated_block);
} else {
const auto kernel_done_address = static_cast<uint16_t>(m_proto_action.enable_lcu().lcu_kernel_done_address());
const auto kernel_done_count = static_cast<uint32_t>(m_proto_action.enable_lcu().lcu_kernel_done_count());
}
Expected<std::map<std::string, hailo_vstream_params_t>> Hef::Impl::make_input_vstream_params(
- const std::string &net_group_name, const std::string &partial_network_name, bool quantized,
+ const std::string &net_group_name, const std::string &network_name, bool quantized,
hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size)
{
std::map<std::string, hailo_vstream_params_t> input_vstreams_params;
auto status = fill_missing_input_vstream_params_with_default(net_group_name,
- partial_network_name, input_vstreams_params, quantized, format_type, timeout_ms, queue_size);
+ network_name, input_vstreams_params, quantized, format_type, timeout_ms, queue_size);
CHECK_SUCCESS_AS_EXPECTED(status);
return input_vstreams_params;
}
Expected<std::map<std::string, hailo_vstream_params_t>> Hef::Impl::make_output_vstream_params(
- const std::string &net_group_name, const std::string &partial_network_name, bool quantized,
+ const std::string &net_group_name, const std::string &network_name, bool quantized,
hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size)
{
std::map<std::string, hailo_vstream_params_t> output_vstreams_params;
auto status = fill_missing_output_vstream_params_with_default(net_group_name,
- partial_network_name, output_vstreams_params, quantized, format_type, timeout_ms, queue_size);
+ network_name, output_vstreams_params, quantized, format_type, timeout_ms, queue_size);
CHECK_SUCCESS_AS_EXPECTED(status);
return output_vstreams_params;
}
hailo_status Hef::Impl::fill_missing_input_vstream_params_with_default(const std::string &net_group_name,
- const std::string &partial_network_name, std::map<std::string, hailo_vstream_params_t> &input_vstreams_params,
+ const std::string &network_name, std::map<std::string, hailo_vstream_params_t> &input_vstreams_params,
bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size)
{
auto network_group_metadata = get_network_group_metadata(net_group_name);
CHECK_EXPECTED_AS_STATUS(network_group_metadata);
- auto input_vstream_infos = network_group_metadata->get_input_vstream_infos(partial_network_name);
+ auto input_vstream_infos = network_group_metadata->get_input_vstream_infos(network_name);
CHECK_EXPECTED_AS_STATUS(input_vstream_infos);
return fill_missing_vstream_params_with_default(input_vstreams_params, input_vstream_infos.value(),
}
hailo_status Hef::Impl::fill_missing_output_vstream_params_with_default(const std::string &net_group_name,
- const std::string &partial_network_name, std::map<std::string, hailo_vstream_params_t> &output_vstream_params,
+ const std::string &network_name, std::map<std::string, hailo_vstream_params_t> &output_vstream_params,
bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size)
{
auto network_group_metadata = get_network_group_metadata(net_group_name);
CHECK_EXPECTED_AS_STATUS(network_group_metadata);
- auto output_vstream_infos = network_group_metadata->get_output_vstream_infos(partial_network_name);
+ auto output_vstream_infos = network_group_metadata->get_output_vstream_infos(network_name);
CHECK_EXPECTED_AS_STATUS(output_vstream_infos);
return fill_missing_vstream_params_with_default(output_vstream_params, output_vstream_infos.value(),
if (network_gorup_metadata->supported_features().multi_network_support) {
CHECK_AS_EXPECTED((net_group.value()->networks_names_size() != 0), HAILO_INTERNAL_FAILURE,
"Hef support multiple networks, but no networks found in the proto");
- for (const auto &network : net_group.value()->networks_names()) {
- auto network_name = net_group_name + HAILO_DEFAULT_NETWORK_NAME_QUALIFIER + network;
+ for (const auto &partial_network_name : net_group.value()->networks_names()) {
+ auto network_name = HefUtils::get_network_name(net_group_name, partial_network_name);
auto params = HailoRTDefaults::get_network_parameters();
results.emplace(std::make_pair(network_name, params));
}
} else {
/* For hefs without the "networks_names" field, build default network name with default params */
auto params = HailoRTDefaults::get_network_parameters();
- auto network = HailoRTDefaults::get_network_name(net_group_name);
- results.emplace(std::make_pair(network, params));
+ auto network_name = HailoRTDefaults::get_network_name(net_group_name);
+ results.emplace(std::make_pair(network_name, params));
}
return results;
NetworkGroupMetadata::NetworkGroupMetadata(const std::string &network_group_name, std::vector<LayerInfo> &&layer_infos,
std::vector<std::string> &&sorted_output_names, NetworkGroupSupportedFeatures &supported_features,
- const std::vector<std::string> &sorted_partial_network_names)
+ const std::vector<std::string> &sorted_network_names)
: m_network_group_name(network_group_name), m_sorted_output_names(std::move(sorted_output_names)), m_supported_features(supported_features),
- m_sorted_partial_network_names(sorted_partial_network_names)
+ m_sorted_network_names(sorted_network_names)
{
for (auto &layer_info : layer_infos) {
if (HAILO_H2D_STREAM == layer_info.direction) {
- m_input_layer_infos[layer_info.partial_network_name].push_back(layer_info);
+ m_input_layer_infos[layer_info.network_name].push_back(layer_info);
} else {
- m_output_layer_infos[layer_info.partial_network_name].push_back(layer_info);
+ m_output_layer_infos[layer_info.network_name].push_back(layer_info);
+ }
+ }
+}
+
+Expected<LayerInfo> NetworkGroupMetadata::get_layer_info_by_stream_name(const std::string &stream_name) const
+{
+ auto layer_infos = get_all_layer_infos();
+ CHECK_EXPECTED(layer_infos);
+ for (auto layer_info : layer_infos.release()) {
+ if (layer_info.name == stream_name) {
+ return layer_info;
}
}
+ LOGGER__ERROR("Failed to find layer with name {}", stream_name);
+ return make_unexpected(HAILO_NOT_FOUND);
}
-Expected<std::vector<LayerInfo>> NetworkGroupMetadata::get_input_layer_infos(const std::string &partial_network_name) const
+Expected<std::vector<LayerInfo>> NetworkGroupMetadata::get_input_layer_infos(const std::string &network_name) const
{
- CHECK_AS_EXPECTED((partial_network_name == HAILO_DEFAULT_PARTIAL_NETWORK_NAME) || contains(m_input_layer_infos, partial_network_name),
- HAILO_NOT_FOUND, "Network name {} is not found in networks metadata", partial_network_name);
+ CHECK_AS_EXPECTED((network_name.empty()) || (network_name == default_network_name()) || contains(m_input_layer_infos, network_name),
+ HAILO_NOT_FOUND, "Network name {} is not found in networks metadata", network_name);
std::vector<LayerInfo> res;
for (auto &layer_infos_pair : m_input_layer_infos) {
- if ((partial_network_name == layer_infos_pair.first) || (partial_network_name == HAILO_DEFAULT_PARTIAL_NETWORK_NAME)) {
+ if ((network_name == layer_infos_pair.first) || (network_name.empty()) || (network_name == default_network_name())) {
res.insert(res.end(), layer_infos_pair.second.begin(), layer_infos_pair.second.end());
}
}
return res;
}
-Expected<std::vector<LayerInfo>> NetworkGroupMetadata::get_output_layer_infos(const std::string &partial_network_name) const
+Expected<std::vector<LayerInfo>> NetworkGroupMetadata::get_output_layer_infos(const std::string &network_name) const
{
- CHECK_AS_EXPECTED((partial_network_name == HAILO_DEFAULT_PARTIAL_NETWORK_NAME) || contains(m_output_layer_infos, partial_network_name),
- HAILO_NOT_FOUND, "Network name {} is not found in networks metadata", partial_network_name);
+ CHECK_AS_EXPECTED((network_name.empty()) || (network_name == default_network_name()) || contains(m_output_layer_infos, network_name),
+ HAILO_NOT_FOUND, "Network name {} is not found in networks metadata", network_name);
std::vector<LayerInfo> res;
for (auto &layer_infos_pair : m_output_layer_infos) {
- if ((partial_network_name == layer_infos_pair.first) || (partial_network_name == HAILO_DEFAULT_PARTIAL_NETWORK_NAME)) {
+ if ((network_name == layer_infos_pair.first) || (network_name.empty()) || (network_name == default_network_name())) {
res.insert(res.end(), layer_infos_pair.second.begin(), layer_infos_pair.second.end());
}
}
return res;
}
-Expected<std::vector<LayerInfo>> NetworkGroupMetadata::get_all_layer_infos(const std::string &partial_network_name) const
+Expected<std::vector<LayerInfo>> NetworkGroupMetadata::get_all_layer_infos(const std::string &network_name) const
{
- auto input_layer_infos = get_input_layer_infos(partial_network_name);
+ auto input_layer_infos = get_input_layer_infos(network_name);
CHECK_EXPECTED(input_layer_infos);
- auto output_layer_infos = get_output_layer_infos(partial_network_name);
+ auto output_layer_infos = get_output_layer_infos(network_name);
CHECK_EXPECTED(output_layer_infos);
std::vector<LayerInfo> res;
return res;
}
-Expected<std::vector<hailo_stream_info_t>> NetworkGroupMetadata::get_input_stream_infos(const std::string &partial_network_name) const
+Expected<std::vector<hailo_stream_info_t>> NetworkGroupMetadata::get_input_stream_infos(const std::string &network_name) const
{
- auto input_layer_infos = get_input_layer_infos(partial_network_name);
+ auto input_layer_infos = get_input_layer_infos(network_name);
CHECK_EXPECTED(input_layer_infos);
return convert_layer_infos_to_stream_infos(input_layer_infos.value());
}
-Expected<std::vector<hailo_stream_info_t>> NetworkGroupMetadata::get_output_stream_infos(const std::string &partial_network_name) const
+Expected<std::vector<hailo_stream_info_t>> NetworkGroupMetadata::get_output_stream_infos(const std::string &network_name) const
{
- auto output_layer_infos = get_output_layer_infos(partial_network_name);
+ auto output_layer_infos = get_output_layer_infos(network_name);
CHECK_EXPECTED(output_layer_infos);
return convert_layer_infos_to_stream_infos(output_layer_infos.value());
}
-Expected<std::vector<hailo_stream_info_t>> NetworkGroupMetadata::get_all_stream_infos(const std::string &partial_network_name) const
+Expected<std::vector<hailo_stream_info_t>> NetworkGroupMetadata::get_all_stream_infos(const std::string &network_name) const
{
- auto input_stream_infos = get_input_stream_infos(partial_network_name);
+ auto input_stream_infos = get_input_stream_infos(network_name);
CHECK_EXPECTED(input_stream_infos);
- auto output_stream_infos = get_output_stream_infos(partial_network_name);
+ auto output_stream_infos = get_output_stream_infos(network_name);
CHECK_EXPECTED(output_stream_infos);
std::vector<hailo_stream_info_t> res;
return res;
}
-Expected<std::vector<hailo_vstream_info_t>> NetworkGroupMetadata::get_input_vstream_infos(const std::string &partial_network_name) const
+Expected<std::vector<hailo_vstream_info_t>> NetworkGroupMetadata::get_input_vstream_infos(const std::string &network_name) const
{
- auto input_layer_infos = get_input_layer_infos(partial_network_name);
+ auto input_layer_infos = get_input_layer_infos(network_name);
CHECK_EXPECTED(input_layer_infos);
return convert_layer_infos_to_vstream_infos(input_layer_infos.value());
}
-Expected<std::vector<hailo_vstream_info_t>> NetworkGroupMetadata::get_output_vstream_infos(const std::string &partial_network_name) const
+Expected<std::vector<hailo_vstream_info_t>> NetworkGroupMetadata::get_output_vstream_infos(const std::string &network_name) const
{
- auto output_layer_infos = get_output_layer_infos(partial_network_name);
+ auto output_layer_infos = get_output_layer_infos(network_name);
CHECK_EXPECTED(output_layer_infos);
auto res = convert_layer_infos_to_vstream_infos(output_layer_infos.value());
return res;
}
-Expected<std::vector<hailo_vstream_info_t>> NetworkGroupMetadata::get_all_vstream_infos(const std::string &partial_network_name) const
+Expected<std::vector<hailo_vstream_info_t>> NetworkGroupMetadata::get_all_vstream_infos(const std::string &network_name) const
{
- auto input_vstream_infos = get_input_vstream_infos(partial_network_name);
+ auto input_vstream_infos = get_input_vstream_infos(network_name);
CHECK_EXPECTED(input_vstream_infos);
- auto output_vstream_infos = get_output_vstream_infos(partial_network_name);
+ auto output_vstream_infos = get_output_vstream_infos(network_name);
CHECK_EXPECTED(output_vstream_infos);
std::vector<hailo_vstream_info_t> res;
{
std::vector<hailo_vstream_info_t> res;
for (auto &layer_info : layer_infos) {
- auto vstream_infos = LayerInfoUtils::get_vstream_infos_from_layer_info(layer_info, m_network_group_name);
+ auto vstream_infos = LayerInfoUtils::get_vstream_infos_from_layer_info(layer_info);
for (const auto &vstream_info : vstream_infos) {
// In case of fused nms layers, several LayerInfos will contain data about the same fused layer
if (!LayerInfoUtils::vstream_info_already_in_vector(res, vstream_info.name)) {
return res;
}
-Expected<std::string> NetworkGroupMetadata::get_partial_network_name(const std::string &network_name) const
-{
- if (network_name.empty()) {
- return HAILO_DEFAULT_PARTIAL_NETWORK_NAME;
- }
-
- for (const auto &partial_network_name : m_sorted_partial_network_names) {
- auto found = network_name.find(HAILO_DEFAULT_NETWORK_NAME_QUALIFIER + partial_network_name);
- if (found != std::string::npos) {
- return Expected<std::string>(partial_network_name);
- }
- }
-
- LOGGER__ERROR("Found no partial network name for network name {}", network_name);
- return make_unexpected(HAILO_NOT_FOUND);
-}
-
Expected<std::vector<hailo_network_info_t>> NetworkGroupMetadata::get_network_infos() const
{
std::vector<hailo_network_info_t> network_infos;
auto net_group_name = network_group_name();
- network_infos.reserve(m_sorted_partial_network_names.size());
- for (auto const &partial_network_name : m_sorted_partial_network_names) {
+ network_infos.reserve(m_sorted_network_names.size());
+ for (auto const &network_name : m_sorted_network_names) {
hailo_network_info_t network_info = {};
- auto network_name = net_group_name + HAILO_DEFAULT_NETWORK_NAME_QUALIFIER + partial_network_name;
CHECK_AS_EXPECTED(HAILO_MAX_NETWORK_NAME_SIZE >= (network_name.length() + 1), HAILO_INTERNAL_FAILURE,
"The network '{}' has a too long name (max is HAILO_MAX_NETWORK_NAME_SIZE)", network_name);
memcpy(network_info.name, network_name.c_str(), network_name.length() + 1);
{
class ResourcesManager;
-class ConfigResources;
+class ConfigBuffer;
class VdmaConfigActivatedNetworkGroup;
using VdmaConfigActiveAppHolder = ActiveNetworkGroupHolder<VdmaConfigActivatedNetworkGroup>;
using ProtoHEFNetworkGroupPtr = std::shared_ptr<ProtoHEFNetworkGroup>;
COMPRESSED_PARAMS,
TRANSPOSE_COMPONENT,
IS_NMS_MULTI_CONTEXT,
- OFFLOAD_ARGMAX
+ OFFLOAD_ARGMAX,
+ PRELIMINARY_RUN_ASAP // Extention added in platform 4.8 release
};
struct HefParsingInfo
bool padded_ddr_buffers;
bool multi_network_support;
bool multi_context;
+ bool preliminary_run_asap;
};
static inline bool is_h2d_boundary_info_layer(const ProtoHEFEdgeLayer& layer)
class NetworkGroupMetadata {
public:
NetworkGroupMetadata(const std::string &network_group_name, std::vector<LayerInfo> &&layer_infos, std::vector<std::string> &&sorted_output_names,
- NetworkGroupSupportedFeatures &supported_features, const std::vector<std::string> &sorted_partial_network_names);
+ NetworkGroupSupportedFeatures &supported_features, const std::vector<std::string> &sorted_network_names);
- Expected<std::vector<LayerInfo>> get_input_layer_infos(const std::string &partial_network_name = HAILO_DEFAULT_PARTIAL_NETWORK_NAME) const;
- Expected<std::vector<LayerInfo>> get_output_layer_infos(const std::string &partial_network_name = HAILO_DEFAULT_PARTIAL_NETWORK_NAME) const;
- Expected<std::vector<LayerInfo>> get_all_layer_infos(const std::string &partial_network_name = HAILO_DEFAULT_PARTIAL_NETWORK_NAME) const;
+ Expected<std::vector<LayerInfo>> get_input_layer_infos(const std::string &network_name = "") const;
+ Expected<std::vector<LayerInfo>> get_output_layer_infos(const std::string &network_name = "") const;
+ Expected<std::vector<LayerInfo>> get_all_layer_infos(const std::string &network_name = "") const;
+ Expected<LayerInfo> get_layer_info_by_stream_name(const std::string &stream_name) const;
- Expected<std::vector<hailo_stream_info_t>> get_input_stream_infos(const std::string &partial_network_name = HAILO_DEFAULT_PARTIAL_NETWORK_NAME) const;
- Expected<std::vector<hailo_stream_info_t>> get_output_stream_infos(const std::string &partial_network_name = HAILO_DEFAULT_PARTIAL_NETWORK_NAME) const;
- Expected<std::vector<hailo_stream_info_t>> get_all_stream_infos(const std::string &partial_network_name = HAILO_DEFAULT_PARTIAL_NETWORK_NAME) const;
+ Expected<std::vector<hailo_stream_info_t>> get_input_stream_infos(const std::string &network_name = "") const;
+ Expected<std::vector<hailo_stream_info_t>> get_output_stream_infos(const std::string &network_name = "") const;
+ Expected<std::vector<hailo_stream_info_t>> get_all_stream_infos(const std::string &network_name = "") const;
- Expected<std::vector<hailo_vstream_info_t>> get_input_vstream_infos(const std::string &partial_network_name = HAILO_DEFAULT_PARTIAL_NETWORK_NAME) const;
- Expected<std::vector<hailo_vstream_info_t>> get_output_vstream_infos(const std::string &partial_network_name = HAILO_DEFAULT_PARTIAL_NETWORK_NAME) const;
- Expected<std::vector<hailo_vstream_info_t>> get_all_vstream_infos(const std::string &partial_network_name = HAILO_DEFAULT_PARTIAL_NETWORK_NAME) const;
+ Expected<std::vector<hailo_vstream_info_t>> get_input_vstream_infos(const std::string &network_name = "") const;
+ Expected<std::vector<hailo_vstream_info_t>> get_output_vstream_infos(const std::string &network_name = "") const;
+ Expected<std::vector<hailo_vstream_info_t>> get_all_vstream_infos(const std::string &network_name = "") const;
Expected<std::vector<std::string>> get_vstream_names_from_stream_name(const std::string &stream_name) const;
Expected<std::vector<std::string>> get_stream_names_from_vstream_name(const std::string &vstream_name) const;
- // Note - network name is build in the following way - "network_group_name / partial_network name"
- // get partial network name returns the part of the name after the network group name and the "/" qualifier.
- // The protobuf hold the partial network name.
- Expected<std::string> get_partial_network_name(const std::string &network_name) const;
-
Expected<std::vector<hailo_network_info_t>> get_network_infos() const;
const std::string &network_group_name() const
return m_network_group_name;
}
+ const std::string default_network_name() const
+ {
+ return HailoRTDefaults::get_network_name(m_network_group_name);
+ }
+
const std::vector<std::string> get_sorted_output_names() const
{
return m_sorted_output_names;
return m_supported_features;
}
- const std::vector<std::string> get_partial_network_names() const
+ const std::vector<std::string> get_network_names() const
{
- return m_sorted_partial_network_names;
+ return m_sorted_network_names;
}
private:
std::string m_network_group_name;
std::vector<std::string> m_sorted_output_names;
NetworkGroupSupportedFeatures m_supported_features;
- std::vector<std::string> m_sorted_partial_network_names;
+ std::vector<std::string> m_sorted_network_names;
};
class Hef::Impl final
Expected<std::vector<hailo_network_info_t>> get_network_infos(const std::string &net_group_name="");
Expected<std::vector<hailo_stream_info_t>> get_input_stream_infos(const std::string &net_group_name="",
- const std::string &partial_network_name="");
+ const std::string &network_name="");
Expected<std::vector<hailo_stream_info_t>> get_output_stream_infos(const std::string &net_group_name="",
- const std::string &partial_network_name="");
+ const std::string &network_name="");
Expected<std::vector<hailo_stream_info_t>> get_all_stream_infos(const std::string &net_group_name="",
- const std::string &partial_network_name="");
+ const std::string &network_name="");
Expected<hailo_stream_info_t> get_stream_info_by_name(const std::string &stream_name,
hailo_stream_direction_t stream_direction, const std::string &net_group_name="");
Expected<std::vector<hailo_vstream_info_t>> get_input_vstream_infos(const std::string &net_group_name="",
- const std::string &partial_network_name="");
+ const std::string &network_name="");
Expected<std::vector<hailo_vstream_info_t>> get_output_vstream_infos(const std::string &net_group_name="",
- const std::string &partial_network_name="");
+ const std::string &network_name="");
Expected<std::vector<hailo_vstream_info_t>> get_all_vstream_infos(const std::string &net_group_name="",
- const std::string &partial_network_name="");
+ const std::string &network_name="");
Expected<std::vector<std::string>> get_sorted_output_names(const std::string &net_group_name="");
Expected<size_t> get_number_of_input_streams(const std::string &net_group_name="");
Expected<size_t> get_number_of_output_streams(const std::string &net_group_name="");
static bool contains_ddr_layers(const ProtoHEFNetworkGroup& net_group);
static hailo_status validate_net_group_unique_layer_names(ProtoHEFNetworkGroupPtr net_group);
Expected<std::vector<hailo_vstream_info_t>> get_network_input_vstream_infos(const std::string &net_group_name="",
- const std::string &partial_network_name="");
+ const std::string &network_name="");
Expected<std::vector<std::string>> get_stream_names_from_vstream_name(const std::string &vstream_name,
const std::string &net_group_name="");
const hailo_mipi_input_stream_params_t &mipi_params);
Expected<std::map<std::string, hailo_vstream_params_t>> make_input_vstream_params(
- const std::string &net_group_name, const std::string &partial_network_name, bool quantized,
+ const std::string &net_group_name, const std::string &network_name, bool quantized,
hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size);
hailo_status fill_missing_input_vstream_params_with_default(const std::string &net_group_name,
- const std::string &partial_network_name, std::map<std::string, hailo_vstream_params_t> &input_vstreams_params,
+ const std::string &network_name, std::map<std::string, hailo_vstream_params_t> &input_vstreams_params,
bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size);
Expected<std::map<std::string, hailo_vstream_params_t>> make_output_vstream_params(
- const std::string &net_group_name, const std::string &partial_network_name, bool quantized,
+ const std::string &net_group_name, const std::string &network_name, bool quantized,
hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size);
hailo_status fill_missing_output_vstream_params_with_default(const std::string &net_group_name,
- const std::string &partial_network_name, std::map<std::string, hailo_vstream_params_t> &output_vstream_params,
+ const std::string &network_name, std::map<std::string, hailo_vstream_params_t> &output_vstream_params,
bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size);
static hailo_status fill_missing_vstream_params_with_default(std::map<std::string, hailo_vstream_params_t> &vstream_params,
std::vector<hailo_vstream_info_t> &name_to_format_info, bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms,
static Expected<HefParsingInfo> get_parsing_info(ProtoHEFNetworkGroupPtr net_group);
Expected<std::map<std::string, hailo_format_t>> get_inputs_vstream_names_and_format_info(
- const std::string &net_group_name, const std::string &partial_network_name);
+ const std::string &net_group_name, const std::string &network_name);
Expected<std::map<std::string, hailo_format_t>> get_outputs_vstream_names_and_format_info(
- const std::string &net_group_name, const std::string &partial_network_name);
+ const std::string &net_group_name, const std::string &network_name);
static Expected<std::string> get_vstream_name_from_original_name_mux(const std::string &original_name, const ProtoHefEdge &layer);
static Expected<std::vector<std::string>> get_original_names_from_vstream_name_mux(const std::string &vstream_name, const ProtoHefEdge &layer);
static Expected<std::vector<hailo_network_info_t>> get_network_infos(const ProtoHEFNetworkGroup &net_group,
const std::string &net_group_name, const NetworkGroupSupportedFeatures &supported_features);
+
+ static std::string get_network_name(const ProtoHEFNetworkGroup &net_group, const std::string &partial_network_name);
+ static std::string get_network_name(const std::string &net_group_name, const std::string &partial_network_name);
+
private:
static hailo_status fill_layer_info_with_base_info(const ProtoHEFEdgeLayerBase &base_info,
const ProtoHEFEdgeConnectionType &edge_connection_type,
const ProtoHEFNetworkGroup &net_group, hailo_stream_direction_t direction,
bool hw_padding_supported, const std::string &partial_network_name, LayerInfo &layer_info);
static hailo_status fill_fused_nms_info(const ProtoHEFEdgeLayerFused &info,
- LayerInfo &layer_info, hailo_quant_info_t &defuse_quant_info, const std::string &partial_network_name);
+ LayerInfo &layer_info, hailo_quant_info_t &defuse_quant_info, const std::string &network_name);
static hailo_status fill_mux_info(const ProtoHEFEdgeLayerMux &info,
const ProtoHEFEdgeConnectionType &edge_connection_type,
const ProtoHEFNetworkGroup &net_group, hailo_stream_direction_t direction,
None,
WriteData,
WriteDataCcw,
+ AddCcwBurst,
CreateDescForCcw,
ReadVdma,
TriggerSequencer,
WaitForModuleConfigDone,
AddDdrPairInfo,
AddDdrBufferingStart,
- AddRrepeated
+ AddRrepeated,
+ StartBurstCreditsTask
};
static Expected<ContextSwitchConfigActionPtr> create(const ProtoHEFAction &proto_action, Device &device,
- std::vector<ConfigResources> &config, const ResourcesManager &resources_manager, const ProtoHEFNetworkGroup &net_group,
+ std::vector<ConfigBuffer> &config, const ResourcesManager &resources_manager, const ProtoHEFNetworkGroup &net_group,
bool support_pre_fetch);
ContextSwitchConfigAction(ContextSwitchConfigAction &&) = default;
{
public:
static Expected<ContextSwitchConfigActionPtr> create(const ProtoHEFAction& proto_action,
- std::vector<ConfigResources> &config, bool support_pre_fetch);
+ std::vector<ConfigBuffer> &config, bool support_pre_fetch);
WriteDataCcwAction(WriteDataCcwAction &&) = default;
WriteDataCcwAction(const WriteDataCcwAction &) = delete;
WriteDataCcwAction &operator=(WriteDataCcwAction &&) = delete;
virtual bool supports_repeated_block() const override;
private:
- WriteDataCcwAction(const ProtoHEFAction& proto_action, std::vector<ConfigResources> &config,
+ WriteDataCcwAction(const ProtoHEFAction& proto_action, ConfigBuffer &config,
bool support_pre_fetch);
- bool should_pad_with_nops();
- hailo_status pad_with_nops(uint8_t cfg_channel_index);
+ bool is_last_ccw_write();
+ hailo_status pad_with_nops();
- std::vector<ConfigResources> &m_config;
+ ConfigBuffer &m_config;
const bool m_support_pre_fetch;
};
+class AddCcwBurstAction : public ContextSwitchConfigAction
+{
+public:
+ static Expected<ContextSwitchConfigActionPtr> create(uint8_t channel_index, uint16_t ccw_bursts);
+
+ virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
+ uint8_t **context_meta_data_head_pointer) override;
+ virtual bool supports_repeated_block() const override;
+
+private:
+ AddCcwBurstAction(uint8_t channel_index, uint16_t ccw_bursts);
+
+ const uint8_t m_channel_index;
+ const uint16_t m_ccw_bursts;
+};
+
class CreateConfigDescAndFetchAction : public ContextSwitchConfigAction
{
public:
- static Expected<ContextSwitchConfigActionPtr> create(std::vector<ConfigResources> &config_resources,
- const std::set<uint8_t> &pending_cfg_ch_buffer, const std::vector<uint16_t> &ccw_burst, bool support_pre_fetch);
+ static Expected<ContextSwitchConfigActionPtr> create(uint8_t channel_index, ConfigBuffer &config_buffer);
+
CreateConfigDescAndFetchAction(CreateConfigDescAndFetchAction &&) = default;
CreateConfigDescAndFetchAction(const CreateConfigDescAndFetchAction &) = delete;
CreateConfigDescAndFetchAction &operator=(CreateConfigDescAndFetchAction &&) = delete;
virtual bool supports_repeated_block() const override;
private:
- CreateConfigDescAndFetchAction(std::vector<ConfigResources> &config, const std::set<uint8_t> &pending_cfg_ch_buffer,
- const std::vector<uint16_t> &ccw_burst, bool support_pre_fetch);
-
- std::vector<ConfigResources> &m_config;
- const std::set<uint8_t> m_pending_cfg_ch_buffer;
- const std::vector<uint16_t> m_ccw_bursts;
- const bool m_support_pre_fetch;
+ CreateConfigDescAndFetchAction(uint8_t channel_index, ConfigBuffer &config_buffer);
+
+ const uint8_t m_channel_index;
+ ConfigBuffer &m_config_buffer;
+};
+
+class StartBurstCreditsTaskAction : public ContextSwitchConfigAction
+{
+public:
+ static Expected<ContextSwitchConfigActionPtr> create();
+
+ StartBurstCreditsTaskAction(StartBurstCreditsTaskAction &&) = default;
+ StartBurstCreditsTaskAction(const StartBurstCreditsTaskAction &) = delete;
+ StartBurstCreditsTaskAction &operator=(StartBurstCreditsTaskAction &&) = delete;
+ StartBurstCreditsTaskAction &operator=(const StartBurstCreditsTaskAction &) = delete;
+ virtual ~StartBurstCreditsTaskAction() = default;
+
+ virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info,
+ uint8_t **context_meta_data_head_pointer) override;
+ virtual bool supports_repeated_block() const override;
+
+private:
+ StartBurstCreditsTaskAction();
};
class RepeatedHeaderAction : public ContextSwitchConfigAction
#include "vstream_internal.hpp"
#include "hailort_defaults.hpp"
#include "context_switch/network_group_internal.hpp"
+#include "context_switch/network_group_wrapper.hpp"
#include <sstream>
{
auto network_infos = net_group.get_network_infos();
CHECK_EXPECTED(network_infos);
- auto is_multi_context = (dynamic_cast<ConfiguredNetworkGroupBase&>(net_group)).get_supported_features().multi_context;
+ auto is_multi_context = (dynamic_cast<ConfiguredNetworkGroupWrapper&>(net_group)).get_configured_network()->get_supported_features().multi_context;
std::map<std::string, std::pair<size_t, size_t>> input_param_count_per_network;
size_t total_inputs_found = 0;
size_t total_outputs_found = 0;
* @brief Manages intermediate buffer for inter-context or ddr channels.
*/
-#include "intermediate_buffer.hpp"
#include "context_switch/multi_context/resource_manager.hpp"
+#include "intermediate_buffer.hpp"
+#include "vdma/sg_buffer.hpp"
+#include "vdma/continuous_buffer.hpp"
+
namespace hailort
{
-Expected<std::unique_ptr<IntermediateBuffer>> IntermediateBuffer::create(Type type, HailoRTDriver &driver,
- const uint32_t transfer_size, const uint16_t batch_size)
+Expected<IntermediateBuffer> IntermediateBuffer::create(HailoRTDriver &driver,
+ ChannelType channel_type, const uint32_t transfer_size, const uint16_t batch_size)
{
- switch (type) {
- case Type::EXTERNAL_DESC:
- return ExternalDescIntermediateBuffer::create(driver, transfer_size, batch_size);
- default:
- LOGGER__ERROR("Invalid intermediate buffer type {}\n", static_cast<int>(type));
- return make_unexpected(HAILO_INVALID_OPERATION);
+ auto buffer_ptr = should_use_ccb(driver, channel_type) ?
+ create_ccb_buffer(driver, transfer_size, batch_size) :
+ create_sg_buffer(driver, transfer_size, batch_size);
+ CHECK_EXPECTED(buffer_ptr);
+
+ return IntermediateBuffer(buffer_ptr.release(), transfer_size, batch_size);
+}
+
+hailo_status IntermediateBuffer::program_inter_context()
+{
+ size_t acc_offset = 0;
+ for (uint16_t i = 0; i < m_max_batch_size; i++) {
+ const auto first_desc_interrupts_domain = VdmaInterruptsDomain::NONE;
+ const auto last_desc_interrupts_domain = ((m_max_batch_size - 1) == i) ?
+ VdmaInterruptsDomain::DEVICE : VdmaInterruptsDomain::NONE;
+ static const auto BUFFER_NOT_CIRCULAR = false;
+ auto desc_count_local = m_buffer->program_descriptors(m_transfer_size, first_desc_interrupts_domain,
+ last_desc_interrupts_domain, acc_offset, BUFFER_NOT_CIRCULAR);
+ CHECK_EXPECTED_AS_STATUS(desc_count_local,
+ "Failed to program descs for intermediate channels. Given batch_size is too big.");
+ acc_offset += desc_count_local.value();
}
+ return HAILO_SUCCESS;
}
-Expected<std::unique_ptr<IntermediateBuffer>> ExternalDescIntermediateBuffer::create(HailoRTDriver &driver,
- const uint32_t transfer_size, const uint16_t transfers_count)
+hailo_status IntermediateBuffer::reprogram_inter_context(uint16_t batch_size)
{
- auto desc_sizes_pair = VdmaDescriptorList::get_desc_buffer_sizes_for_single_transfer(driver,
- transfers_count, transfers_count, transfer_size);
- CHECK_EXPECTED(desc_sizes_pair);
- auto desc_page_size = desc_sizes_pair->first;
- auto descs_count = desc_sizes_pair->second;
+ const auto prev_batch_size = m_dynamic_batch_size;
+ auto status = set_dynamic_batch_size(batch_size);
+ CHECK_SUCCESS(status);
- auto buffer = VdmaBuffer::create((descs_count * desc_page_size), HailoRTDriver::DmaDirection::BOTH, driver);
- CHECK_EXPECTED(buffer);
+ if (prev_batch_size == m_dynamic_batch_size) {
+ LOGGER__TRACE("Batch size hasn't changed ({}); nothing to be done.", batch_size);
+ return HAILO_SUCCESS;
+ }
- auto desc_buffer = VdmaDescriptorList::create(descs_count, desc_page_size, driver);
- CHECK_EXPECTED(desc_buffer);
+ status = m_buffer->reprogram_device_interrupts_for_end_of_batch(m_transfer_size, prev_batch_size,
+ VdmaInterruptsDomain::NONE);
+ CHECK_SUCCESS(status, "Failed reprogramming device interrupts for the end of the previous batch (size {})",
+ prev_batch_size);
+ status = m_buffer->reprogram_device_interrupts_for_end_of_batch(m_transfer_size, m_dynamic_batch_size,
+ VdmaInterruptsDomain::DEVICE);
+ CHECK_SUCCESS(status, "Failed reprogramming device interrupts for the end of the current batch (size {})",
+ m_dynamic_batch_size);
- // On dram-dma all descriptors should have channel index, until we implement CCB,
- // we use some fake channel index. Currently the channel_index is not in used by
- // the hw. TODO HRT-5835: remove channel_index.
- const uint8_t channel_index = 0;
- auto status = desc_buffer->configure_to_use_buffer(buffer.value(), channel_index);
- CHECK_SUCCESS_AS_EXPECTED(status);
+ return HAILO_SUCCESS;
+}
- auto intermediate_buffer = make_unique_nothrow<ExternalDescIntermediateBuffer>(buffer.release(), desc_buffer.release(),
- transfer_size, transfers_count);
- CHECK_NOT_NULL_AS_EXPECTED(intermediate_buffer, HAILO_OUT_OF_HOST_MEMORY);
+Expected<uint16_t> IntermediateBuffer::program_ddr()
+{
+ const auto interrupts_domain = VdmaInterruptsDomain::NONE;
+ const auto total_size = m_buffer->descs_count() * m_buffer->desc_page_size();
- return std::unique_ptr<IntermediateBuffer>(intermediate_buffer.release());
+ auto desc_count_local = m_buffer->program_descriptors(total_size,
+ interrupts_domain, interrupts_domain, 0, true);
+ CHECK_EXPECTED(desc_count_local);
+
+ return static_cast<uint16_t>(desc_count_local.release());
}
-hailo_status ExternalDescIntermediateBuffer::program_inter_context()
+uint64_t IntermediateBuffer::dma_address() const
{
- size_t acc_offset = 0;
- for (uint16_t i = 0; i < m_transfers_count; i++) {
- auto first_desc_interrupts_domain = VdmaInterruptsDomain::NONE;
- auto last_desc_interrupts_domain = ((m_transfers_count - 1) == i) ? VdmaInterruptsDomain::DEVICE :
- VdmaInterruptsDomain::NONE;
- auto desc_count_local = m_desc_list.program_descriptors(m_transfer_size, first_desc_interrupts_domain,
- last_desc_interrupts_domain, acc_offset, false);
- CHECK_EXPECTED_AS_STATUS(desc_count_local,
- "Failed to program descs for intermediate channels. Given batch_size is too big.");
- acc_offset += desc_count_local.value();
- }
- return HAILO_SUCCESS;
+ return m_buffer->dma_address();
+}
+
+uint32_t IntermediateBuffer::descriptors_in_frame() const
+{
+ return m_buffer->descriptors_in_buffer(m_transfer_size);
}
-Expected<uint16_t> ExternalDescIntermediateBuffer::program_ddr()
+uint16_t IntermediateBuffer::desc_page_size() const
{
- return m_desc_list.program_descs_for_ddr_transfers(m_desc_list.desc_page_size(), false, 1,
- static_cast<uint32_t>(m_desc_list.count()), 0, true);
+ return m_buffer->desc_page_size();
}
-Expected<uint16_t> ExternalDescIntermediateBuffer::program_host_managed_ddr(uint16_t row_size, uint32_t buffered_rows,
- uint16_t initial_desc_offset)
+uint32_t IntermediateBuffer::descs_count() const
{
- return m_desc_list.program_descs_for_ddr_transfers(row_size, true, DDR_NUMBER_OF_ROWS_PER_INTERRUPT,
- buffered_rows, initial_desc_offset, true);
+ return m_buffer->descs_count();
+}
+
+uint8_t IntermediateBuffer::depth()
+{
+ // TODO HRT-6763: remove this function, use desc count instead
+ auto count = m_buffer->descs_count();
+
+ uint32_t depth = 0;
+ while (count >>= 1) {
+ ++depth;
+ }
+ assert(IS_FIT_IN_UINT8(depth));
+ return static_cast<uint8_t>(depth);
}
-Expected<Buffer> ExternalDescIntermediateBuffer::read()
+Expected<Buffer> IntermediateBuffer::read()
{
- const auto size = m_transfer_size * m_transfers_count;
- assert(size <= m_buffer.size());
+ const auto size = m_transfer_size * m_dynamic_batch_size;
+ assert(size <= m_buffer->size());
auto res = Buffer::create(size);
CHECK_EXPECTED(res);
- auto status = m_buffer.read(res->data(), size, 0);
+ auto status = m_buffer->read(res->data(), size, 0);
CHECK_SUCCESS_AS_EXPECTED(status);
return res.release();
}
+CONTROL_PROTOCOL__host_buffer_info_t IntermediateBuffer::get_host_buffer_info() const
+{
+ CONTROL_PROTOCOL__host_buffer_info_t buffer_info = {};
+
+ buffer_info.buffer_type = static_cast<uint8_t>((m_buffer->type() == vdma::VdmaBuffer::Type::SCATTER_GATHER) ?
+ CONTROL_PROTOCOL__HOST_BUFFER_TYPE_EXTERNAL_DESC :
+ CONTROL_PROTOCOL__HOST_BUFFER_TYPE_CCB);
+ buffer_info.dma_address = dma_address();
+ buffer_info.desc_page_size = desc_page_size();
+ buffer_info.total_desc_count = descs_count();
+ buffer_info.bytes_in_pattern = m_transfer_size;
+
+ return buffer_info;
+}
+
+Expected<std::unique_ptr<vdma::VdmaBuffer>> IntermediateBuffer::create_sg_buffer(HailoRTDriver &driver,
+ const uint32_t transfer_size, const uint16_t batch_size)
+{
+ auto desc_sizes_pair = VdmaDescriptorList::get_desc_buffer_sizes_for_single_transfer(driver,
+ batch_size, batch_size, transfer_size);
+ CHECK_EXPECTED(desc_sizes_pair);
+ auto desc_page_size = desc_sizes_pair->first;
+ auto descs_count = desc_sizes_pair->second;
+
+ // On dram-dma all descriptors should have channel index, until we implement CCB,
+ // we use some fake channel index. Currently the channel_index is not in used by
+ // the hw. TODO HRT-5835: remove channel_index.
+ const uint8_t channel_index = 0;
+ auto buffer = vdma::SgBuffer::create(driver, descs_count, desc_page_size,
+ HailoRTDriver::DmaDirection::BOTH, channel_index);
+ CHECK_EXPECTED(buffer);
+
+ auto buffer_ptr = make_unique_nothrow<vdma::SgBuffer>(buffer.release());
+ CHECK_NOT_NULL_AS_EXPECTED(buffer_ptr, HAILO_OUT_OF_HOST_MEMORY);
+
+ return std::unique_ptr<vdma::VdmaBuffer>(std::move(buffer_ptr));
+}
+
+IntermediateBuffer::IntermediateBuffer(std::unique_ptr<vdma::VdmaBuffer> &&buffer, uint32_t transfer_size,
+ uint16_t batch_size) :
+ m_buffer(std::move(buffer)),
+ m_transfer_size(transfer_size),
+ m_max_batch_size(batch_size),
+ m_dynamic_batch_size(batch_size)
+{}
+
+hailo_status IntermediateBuffer::set_dynamic_batch_size(uint16_t batch_size)
+{
+ if (CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE == batch_size) {
+ LOGGER__TRACE("Received CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE == batch_size; "
+ "Leaving previously set value of {}", m_dynamic_batch_size);
+ } else {
+ CHECK(batch_size <= m_max_batch_size, HAILO_INVALID_ARGUMENT,
+ "batch_size ({}) must be <= than m_max_batch_size ({})",
+ batch_size, m_max_batch_size);
+
+ LOGGER__TRACE("Setting intermediate buffer's batch_size to {}", batch_size);
+ m_dynamic_batch_size = batch_size;
+ }
+
+ return HAILO_SUCCESS;
+}
+
+Expected<std::unique_ptr<vdma::VdmaBuffer>> IntermediateBuffer::create_ccb_buffer(HailoRTDriver &driver,
+ const uint32_t transfer_size, const uint16_t batch_size)
+{
+ // The first 12 channels in D2H CCB ("regular channels") requires that the amount of descriptors will be a power
+ // of 2. Altough the 4 last channels ("enhanced channels") don't have this requirements, we keep the code the same.
+ auto buffer_size = vdma::ContinuousBuffer::get_buffer_size_desc_power2(transfer_size * batch_size);
+ auto buffer = vdma::ContinuousBuffer::create(buffer_size, driver);
+ CHECK_EXPECTED(buffer);
+
+ auto buffer_ptr = make_unique_nothrow<vdma::ContinuousBuffer>(buffer.release());
+ CHECK_NOT_NULL_AS_EXPECTED(buffer_ptr, HAILO_OUT_OF_HOST_MEMORY);
+
+ return std::unique_ptr<vdma::VdmaBuffer>(std::move(buffer_ptr));
+}
+
+bool IntermediateBuffer::should_use_ccb(HailoRTDriver &driver, ChannelType channel_type)
+{
+ if (ChannelType::DDR == channel_type) {
+ // TODO HRT-6645: remove this if
+ return false;
+ }
+
+ switch (driver.dma_type()) {
+ case HailoRTDriver::DmaType::PCIE:
+ return false;
+ case HailoRTDriver::DmaType::DRAM:
+ return true;
+ default:
+ assert(true);
+ return false;
+ }
+}
+
} /* namespace hailort */
#define _HAILO_INTERMEDIATE_BUFFER_HPP_
#include "os/hailort_driver.hpp"
-#include "vdma_buffer.hpp"
-#include "vdma_descriptor_list.hpp"
+#include "vdma/vdma_buffer.hpp"
#include "hailo/expected.hpp"
#include "hailo/buffer.hpp"
+#include "control_protocol.h"
namespace hailort
{
-class IntermediateBuffer {
+class IntermediateBuffer final {
public:
-
- enum class Type {
- EXTERNAL_DESC
+ enum class ChannelType {
+ INTER_CONTEXT,
+ DDR
};
- static Expected<std::unique_ptr<IntermediateBuffer>> create(Type type, HailoRTDriver &driver,
- const uint32_t transfer_size, const uint16_t batch_size);
-
- virtual ~IntermediateBuffer() = default;
- IntermediateBuffer(const IntermediateBuffer &) = delete;
- IntermediateBuffer& operator=(const IntermediateBuffer &) = delete;
- IntermediateBuffer(IntermediateBuffer &&) = default;
- IntermediateBuffer& operator=(IntermediateBuffer &&) = delete;
-
-
- virtual hailo_status program_inter_context() = 0;
-
- // Returns the amount of programed descriptors
- virtual Expected<uint16_t> program_ddr() = 0;
- virtual Expected<uint16_t> program_host_managed_ddr(uint16_t row_size, uint32_t buffered_rows,
- uint16_t initial_desc_offset) = 0;
-
- virtual uint64_t dma_address() const = 0;
- virtual uint16_t descriptors_in_frame() const = 0;
- virtual uint16_t desc_page_size() const = 0;
- virtual uint16_t descs_count() const = 0;
- virtual uint8_t depth() const = 0;
-
- // Should be only used for host managed ddr buffer, in the future this function may return nullptr (on CCB
- // case where there is no descriptors list)
- virtual VdmaDescriptorList* get_desc_list() = 0;
-
- virtual Expected<Buffer> read() = 0;
-
-protected:
- IntermediateBuffer() = default;
-};
-
-class ExternalDescIntermediateBuffer : public IntermediateBuffer
-{
-public:
-
- static Expected<std::unique_ptr<IntermediateBuffer>> create(HailoRTDriver &driver, const uint32_t transfer_size,
- const uint16_t batch_size);
-
- ExternalDescIntermediateBuffer(VdmaBuffer &&buffer, VdmaDescriptorList &&desc_list,
- const uint32_t transfer_size, const uint32_t transfers_count) :
- m_buffer(std::move(buffer)), m_desc_list(std::move(desc_list)),
- m_transfer_size(transfer_size), m_transfers_count(transfers_count) {};
-
- hailo_status program_inter_context() override;
+ static Expected<IntermediateBuffer> create(HailoRTDriver &driver,
+ ChannelType channel_type, const uint32_t transfer_size, const uint16_t batch_size);
+ // TODO: create two subclasses - one for ddr buffers and one for intercontext buffers (HRT-6784)
+ hailo_status program_inter_context();
+ // This is to be called after program_inter_context
+ hailo_status reprogram_inter_context(uint16_t batch_size);
// Returns the amount of programed descriptors
- Expected<uint16_t> program_ddr() override;
- Expected<uint16_t> program_host_managed_ddr(uint16_t row_size, uint32_t buffered_rows,
- uint16_t initial_desc_offset) override;
-
- uint64_t dma_address() const override
- {
- return m_desc_list.dma_address();
- }
-
- uint16_t descriptors_in_frame() const override
- {
- return static_cast<uint16_t>(m_desc_list.descriptors_in_buffer(m_transfer_size));
- }
+ Expected<uint16_t> program_ddr();
+ uint64_t dma_address() const;
+ uint32_t descriptors_in_frame() const;
+ uint16_t desc_page_size() const;
+ uint32_t descs_count() const;
+ uint8_t depth();
+ Expected<Buffer> read();
- uint16_t desc_page_size() const override
- {
- return m_desc_list.desc_page_size();
- }
+ CONTROL_PROTOCOL__host_buffer_info_t get_host_buffer_info() const;
- uint16_t descs_count() const override
- {
- return static_cast<uint16_t>(m_desc_list.count());
- }
-
- uint8_t depth() const override
- {
- return m_desc_list.depth();
- }
-
- // Should be only used for host managed ddr buffer, in the future this function may return nullptr (on CCB
- // case where there is no descriptors list)
- VdmaDescriptorList* get_desc_list() override
- {
- return &m_desc_list;
- }
+private:
+ IntermediateBuffer(std::unique_ptr<vdma::VdmaBuffer> &&buffer, uint32_t transfer_size, uint16_t batch_size);
+ hailo_status set_dynamic_batch_size(uint16_t batch_size);
- Expected<Buffer> read() override;
+ static Expected<std::unique_ptr<vdma::VdmaBuffer>> create_sg_buffer(HailoRTDriver &driver,
+ const uint32_t transfer_size, const uint16_t batch_size);
+ static Expected<std::unique_ptr<vdma::VdmaBuffer>> create_ccb_buffer(HailoRTDriver &driver,
+ const uint32_t transfer_size, const uint16_t batch_size);
-private:
+ static bool should_use_ccb(HailoRTDriver &driver, ChannelType channel_type);
- VdmaBuffer m_buffer;
- VdmaDescriptorList m_desc_list;
+ std::unique_ptr<vdma::VdmaBuffer> m_buffer;
const uint32_t m_transfer_size;
- const uint32_t m_transfers_count;
+ const uint16_t m_max_batch_size;
+ uint16_t m_dynamic_batch_size;
};
} /* namespace hailort */
hailo_nms_info_t nms_info;
uint32_t height_gcd;
std::vector<uint32_t> height_ratios;
- // Note - network name as seen by the user is build in the following way - "network_group_name / partial_network name"
- // In layer info scope - we would use the partial network name only.
- std::string partial_network_name;
+ std::string network_name;
// Simulation Info
BufferIndices buffer_indices;
return false;
}
- static std::vector<hailo_vstream_info_t> get_vstream_infos_from_layer_info(const LayerInfo &layer_info, const std::string &network_group_name)
+ static std::vector<hailo_vstream_info_t> get_vstream_infos_from_layer_info(const LayerInfo &layer_info)
{
std::vector<hailo_vstream_info_t> res = {};
if (layer_info.is_mux) {
for (auto &pred : layer_info.predecessor) {
- auto vstream_infos = get_vstream_infos_from_layer_info(pred, network_group_name);
+ auto vstream_infos = get_vstream_infos_from_layer_info(pred);
res.insert(res.end(), vstream_infos.begin(), vstream_infos.end());
}
} else if (layer_info.is_defused_nms) {
for (auto &fused_nms : layer_info.fused_nms_layer) {
// In case of fused nms layers, several LayerInfos will contain data about the same fused layer
if (!vstream_info_already_in_vector(res, fused_nms.name)) {
- auto vstream_info = get_vstream_info_from_layer_info_impl(fused_nms, network_group_name);
+ auto vstream_info = get_vstream_info_from_layer_info_impl(fused_nms);
res.push_back(vstream_info);
}
}
} else {
- auto vstream_info = get_vstream_info_from_layer_info_impl(layer_info, network_group_name);
+ auto vstream_info = get_vstream_info_from_layer_info_impl(layer_info);
res.push_back(vstream_info);
}
}
private:
- static hailo_vstream_info_t get_vstream_info_from_layer_info_impl(const LayerInfo &layer_info, const std::string &network_group_name)
+ static hailo_vstream_info_t get_vstream_info_from_layer_info_impl(const LayerInfo &layer_info)
{
hailo_vstream_info_t res = {};
res.format.type = layer_info.format.type;
res.direction = layer_info.direction;
assert(layer_info.name.length() < HAILO_MAX_STREAM_NAME_SIZE);
strncpy(res.name, layer_info.name.c_str(), layer_info.name.length() + 1);
- auto network_name = network_group_name + HAILO_DEFAULT_NETWORK_NAME_QUALIFIER + layer_info.partial_network_name;
- assert(network_name.length() < HAILO_MAX_NETWORK_NAME_SIZE);
- strncpy(res.network_name, network_name.c_str(), network_name.length() + 1);
+ assert(layer_info.network_name.length() < HAILO_MAX_NETWORK_NAME_SIZE);
+ strncpy(res.network_name, layer_info.network_name.c_str(), layer_info.network_name.length() + 1);
res.quant_info = layer_info.quant_info;
return res;
return control_mipi_params;
}
-hailo_status MipiInputStream::activate_stream()
+// Note: Mipi streams don't work with dynamic batch sizes
+hailo_status MipiInputStream::activate_stream(uint16_t /* dynamic_batch_size */)
{
hailo_status status = HAILO_UNINITIALIZED;
CONTROL_PROTOCOL__config_stream_params_t params = {};
virtual ~MipiInputStream();
- virtual hailo_status activate_stream() override;
+ virtual hailo_status activate_stream(uint16_t dynamic_batch_size) override;
virtual hailo_status deactivate_stream() override;
virtual hailo_stream_interface_t get_interface() const override { return HAILO_STREAM_INTERFACE_MIPI; }
virtual std::chrono::milliseconds get_timeout() const override;
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file network_group_scheduler.cpp
+ * @brief: Network scheduler
+ **/
+
+#include "network_group_scheduler.hpp"
+#include "context_switch/network_group_internal.hpp"
+#include "hef_internal.hpp"
+#include "vdevice_stream.hpp"
+#include "vdma_stream.hpp"
+
+namespace hailort
+{
+
+Expected<NetworkGroupSchedulerPtr> NetworkGroupScheduler::create_shared(hailo_scheduling_algorithm_t algorithm)
+{
+ auto ptr = make_shared_nothrow<NetworkGroupScheduler>(algorithm);
+ CHECK_AS_EXPECTED(nullptr != ptr, HAILO_OUT_OF_HOST_MEMORY);
+
+ return ptr;
+}
+
+hailo_status NetworkGroupScheduler::SchedulerIdleGuard::set_scheduler(std::shared_ptr<NetworkGroupScheduler> scheduler)
+{
+ CHECK(nullptr != scheduler, HAILO_INTERNAL_FAILURE);
+ m_scheduler = scheduler;
+ m_scheduler->force_idle_state();
+ return HAILO_SUCCESS;
+}
+
+NetworkGroupScheduler::SchedulerIdleGuard::~SchedulerIdleGuard()
+{
+ if (m_scheduler) {
+ m_scheduler->resume_from_idle_state();
+ }
+}
+
+void NetworkGroupScheduler::force_idle_state()
+{
+ {
+ std::unique_lock<std::mutex> lock(m_before_read_write_mutex);
+ m_write_read_cv.wait(lock, [this] {
+ return has_current_ng_finished();
+ });
+ deactivate_network_group();
+ m_forced_idle_state = true;
+ }
+ m_write_read_cv.notify_all();
+}
+
+void NetworkGroupScheduler::resume_from_idle_state()
+{
+ {
+ std::unique_lock<std::mutex> lock(m_before_read_write_mutex);
+ m_forced_idle_state = false;
+ }
+ m_write_read_cv.notify_all();
+}
+
+Expected<network_group_handle_t> NetworkGroupScheduler::add_network_group(std::weak_ptr<ConfiguredNetworkGroup> added_cng)
+{
+ network_group_handle_t network_group_handle = INVALID_NETWORK_GROUP_HANDLE;
+ {
+ std::unique_lock<std::mutex> lock(m_before_read_write_mutex);
+ network_group_handle = static_cast<uint32_t>(m_cngs.size());
+
+ m_cngs.emplace_back(added_cng);
+ m_timeout_per_network_group[network_group_handle] = DEFAULT_SCHEDULER_TIMEOUT;
+ m_last_run_time_stamp[network_group_handle] = {}; // Default c'tor to mark this network_group didn't run yet
+
+ auto added_cng_ptr = added_cng.lock();
+ CHECK_AS_EXPECTED(added_cng_ptr, HAILO_INTERNAL_FAILURE);
+
+ auto stream_infos = added_cng_ptr->get_all_stream_infos();
+ CHECK_EXPECTED(stream_infos);
+
+ // Prepare empty counters for the added cng
+ for (const auto &stream_info : stream_infos.value()) {
+ m_should_ng_stop[network_group_handle][stream_info.name] = false;
+ m_min_threshold_per_stream[network_group_handle][stream_info.name] = DEFAULT_SCHEDULER_MIN_THRESHOLD;
+ if (HAILO_H2D_STREAM == stream_info.direction) {
+ m_requested_write[network_group_handle][stream_info.name] = 0;
+ m_written_buffer[network_group_handle][stream_info.name] = 0;
+ m_sent_pending_buffer[network_group_handle][stream_info.name] = 0;
+ m_finished_sent_pending_buffer[network_group_handle][stream_info.name] = 0;
+
+ auto event = Event::create_shared(Event::State::signalled);
+ CHECK_AS_EXPECTED(nullptr != event, HAILO_OUT_OF_HOST_MEMORY);
+
+ m_write_buffer_events[network_group_handle][stream_info.name] = event;
+ } else {
+ m_allowed_read[network_group_handle][stream_info.name] = 0;
+ m_finished_read[network_group_handle][stream_info.name] = 0;
+ }
+ }
+ }
+ m_write_read_cv.notify_all();
+ return network_group_handle;
+}
+
+hailo_status NetworkGroupScheduler::wait_for_write(const network_group_handle_t &network_group_handle, const std::string &stream_name)
+{
+ {
+ std::unique_lock<std::mutex> lock(m_before_read_write_mutex);
+ assert(contains(m_requested_write, network_group_handle));
+ assert(contains(m_write_buffer_events, network_group_handle));
+ if ((nullptr != m_ang) && m_switching_network_group &&
+ (m_requested_write[network_group_handle][stream_name] == get_max_value_of_unordered_map(m_requested_write[network_group_handle]))) {
+ auto status = m_write_buffer_events[network_group_handle][stream_name]->reset();
+ CHECK_SUCCESS(status);
+ }
+ }
+
+ auto status = m_write_buffer_events[network_group_handle][stream_name]->wait(std::chrono::milliseconds(HAILO_INFINITE));
+ CHECK_SUCCESS(status);
+
+ {
+ std::unique_lock<std::mutex> lock(m_before_read_write_mutex);
+
+ assert(contains(m_should_ng_stop, network_group_handle));
+ if (m_should_ng_stop[network_group_handle][stream_name]) {
+ return HAILO_STREAM_INTERNAL_ABORT;
+ }
+
+ m_requested_write[network_group_handle][stream_name]++;
+
+ if ((nullptr != m_ang) && (m_current_network_group == network_group_handle)) {
+ m_has_current_ng_finished = false;
+ }
+
+ status = allow_writes_for_other_inputs_if_needed(network_group_handle);
+ CHECK_SUCCESS(status);
+ }
+
+ m_write_read_cv.notify_all();
+
+ return HAILO_SUCCESS;
+}
+
+hailo_status NetworkGroupScheduler::allow_writes_for_other_inputs_if_needed(const network_group_handle_t &network_group_handle)
+{
+ if (!m_has_current_ng_finished && m_switching_network_group) {
+ auto max_write = get_max_value_of_unordered_map(m_requested_write[network_group_handle]);
+ for (auto &name_event_pair : m_write_buffer_events[network_group_handle]) {
+ if (m_requested_write[network_group_handle][name_event_pair.first] < max_write) {
+ auto status = name_event_pair.second->signal();
+ CHECK_SUCCESS(status);
+ }
+ }
+ }
+ return HAILO_SUCCESS;
+}
+
+hailo_status NetworkGroupScheduler::signal_write_finish(const network_group_handle_t &network_group_handle, const std::string &stream_name)
+{
+ {
+ std::unique_lock<std::mutex> lock(m_before_read_write_mutex);
+
+ assert(contains(m_should_ng_stop, network_group_handle));
+ if (m_should_ng_stop[network_group_handle][stream_name]) {
+ return HAILO_STREAM_INTERNAL_ABORT;
+ }
+
+ assert(contains(m_written_buffer, network_group_handle));
+ assert(contains(m_written_buffer[network_group_handle], stream_name));
+ m_written_buffer[network_group_handle][stream_name]++;
+
+ auto status = switch_network_group_if_idle(network_group_handle, lock);
+ CHECK_SUCCESS(status);
+
+ status = switch_network_group_if_should_be_next(network_group_handle, lock);
+ CHECK_SUCCESS(status);
+
+ status = send_all_pending_buffers(network_group_handle, lock);
+ if (HAILO_STREAM_INTERNAL_ABORT == status) {
+ LOGGER__INFO("send_all_pending_buffers has failed with status=HAILO_STREAM_INTERNAL_ABORT");
+ return status;
+ }
+ CHECK_SUCCESS(status);
+ }
+ m_write_read_cv.notify_all();
+
+ return HAILO_SUCCESS;
+}
+
+hailo_status NetworkGroupScheduler::switch_network_group_if_idle(const network_group_handle_t &network_group_handle, std::unique_lock<std::mutex> &read_write_lock)
+{
+ if (!m_forced_idle_state && !m_switching_network_group && m_has_current_ng_finished &&
+ ((nullptr == m_ang) || (network_group_handle != m_current_network_group)) && is_network_group_ready(network_group_handle)) {
+ auto status = activate_network_group(network_group_handle, read_write_lock);
+ if (HAILO_STREAM_INTERNAL_ABORT == status) {
+ return status;
+ }
+ CHECK_SUCCESS(status);
+ }
+
+ return HAILO_SUCCESS;
+}
+
+hailo_status NetworkGroupScheduler::activate_network_group(const network_group_handle_t &network_group_handle, std::unique_lock<std::mutex> &read_write_lock)
+{
+ deactivate_network_group();
+
+ m_switching_network_group = false;
+ auto status = allow_all_writes();
+ CHECK_SUCCESS(status);
+
+ assert(m_cngs.size() > network_group_handle);
+ auto cng = m_cngs[network_group_handle].lock();
+ CHECK(cng, HAILO_INTERNAL_FAILURE);
+
+ auto cng_base = std::dynamic_pointer_cast<ConfiguredNetworkGroupBase>(cng);
+ auto expected_ang = cng_base->force_activate();
+ CHECK_EXPECTED_AS_STATUS(expected_ang);
+ m_last_run_time_stamp[network_group_handle] = std::chrono::steady_clock::now(); // Mark last timestamp on activation
+
+ m_ang = expected_ang.release();
+
+ m_current_network_group = network_group_handle;
+ m_has_current_ng_finished = false;
+
+ status = send_all_pending_buffers(network_group_handle, read_write_lock);
+ if (HAILO_STREAM_INTERNAL_ABORT == status) {
+ LOGGER__INFO("send_all_pending_buffers has failed with status=HAILO_STREAM_INTERNAL_ABORT");
+ return status;
+ }
+ CHECK_SUCCESS(status);
+
+ return HAILO_SUCCESS;
+}
+
+hailo_status NetworkGroupScheduler::allow_all_writes()
+{
+ for (auto &name_dict_pair : m_write_buffer_events) {
+ for (auto &name_event_pair : name_dict_pair.second) {
+ auto status = name_event_pair.second->signal();
+ CHECK_SUCCESS(status);
+ }
+ }
+ return HAILO_SUCCESS;
+}
+
+hailo_status NetworkGroupScheduler::send_all_pending_buffers(const network_group_handle_t &network_group_handle, std::unique_lock<std::mutex> &read_write_lock)
+{
+ if ((nullptr == m_ang) || (m_current_network_group != network_group_handle)) {
+ return HAILO_SUCCESS;
+ }
+
+ while (true) {
+ uint32_t finished_sending_count = 0;
+ for (auto &name_counter_pair : m_written_buffer[network_group_handle]) {
+ if (m_sent_pending_buffer[network_group_handle][name_counter_pair.first] < name_counter_pair.second) {
+ auto status = send_pending_buffer(network_group_handle, name_counter_pair.first, read_write_lock);
+ if (HAILO_STREAM_INTERNAL_ABORT == status) {
+ LOGGER__INFO("send_pending_buffer has failed with status=HAILO_STREAM_INTERNAL_ABORT");
+ return status;
+ }
+ CHECK_SUCCESS(status);
+ } else {
+ finished_sending_count++;
+ }
+ }
+ if (finished_sending_count == m_written_buffer[network_group_handle].size()) {
+ break;
+ }
+ }
+
+ return HAILO_SUCCESS;
+}
+
+hailo_status NetworkGroupScheduler::send_pending_buffer(const network_group_handle_t &network_group_handle, const std::string &stream_name,
+ std::unique_lock<std::mutex> &read_write_lock)
+{
+ assert(m_cngs.size() > network_group_handle);
+ auto current_cng = m_cngs[network_group_handle].lock();
+ CHECK(current_cng, HAILO_INTERNAL_FAILURE);
+
+ auto input_stream = current_cng->get_input_stream_by_name(stream_name);
+ CHECK_EXPECTED_AS_STATUS(input_stream);
+
+ m_has_current_ng_finished = false;
+
+ VDeviceInputStream &vdevice_input = dynamic_cast<VDeviceInputStream&>(input_stream->get());
+ auto pending_buffer_state = vdevice_input.send_pending_buffer();
+ CHECK_EXPECTED_AS_STATUS(pending_buffer_state);
+
+ assert(contains(m_sent_pending_buffer, network_group_handle));
+ m_sent_pending_buffer[network_group_handle][stream_name]++;
+
+ auto status = pending_buffer_state->finish(vdevice_input.get_timeout(), read_write_lock);
+ if (HAILO_STREAM_INTERNAL_ABORT == status) {
+ LOGGER__INFO("finish has failed with status=HAILO_STREAM_INTERNAL_ABORT");
+ return status;
+ }
+ CHECK_SUCCESS(status);
+
+ assert(contains(m_finished_sent_pending_buffer, network_group_handle));
+ m_finished_sent_pending_buffer[network_group_handle][stream_name]++;
+
+ // Update m_has_current_ng_finished here because after finishing send pending buffer the network group can actually be finished
+ m_has_current_ng_finished = has_current_ng_finished();
+
+ return HAILO_SUCCESS;
+}
+
+void NetworkGroupScheduler::deactivate_network_group()
+{
+ if (m_ang) {
+ reset_current_ng_counters();
+ m_ang.reset();
+ m_last_run_time_stamp[m_current_network_group] = std::chrono::steady_clock::now(); // Mark last timestamp on deactivation
+ }
+}
+
+hailo_status NetworkGroupScheduler::switch_network_group_if_should_be_next(const network_group_handle_t &network_group_handle,
+ std::unique_lock<std::mutex> &read_write_lock)
+{
+ // Checking (nullptr == m_ang) for activating the first time the scheduler is running
+ if (!m_forced_idle_state && m_switching_network_group && m_has_current_ng_finished && is_network_group_ready(network_group_handle) &&
+ ((nullptr == m_ang) || (m_next_network_group == network_group_handle))) {
+ auto status = activate_network_group(network_group_handle, read_write_lock);
+ if (HAILO_STREAM_INTERNAL_ABORT == status) {
+ return status;
+ }
+ }
+
+ return HAILO_SUCCESS;
+}
+
+bool NetworkGroupScheduler::is_network_group_ready(const network_group_handle_t &network_group_handle)
+{
+ assert(contains(m_written_buffer, network_group_handle));
+ assert(contains(m_timeout_per_network_group, network_group_handle));
+ assert(contains(m_min_threshold_per_stream, network_group_handle));
+
+ // TODO: move inside the for-loop when timeout-per-network will be supported
+ bool timeout_passed = (m_timeout_per_network_group[network_group_handle] <
+ (std::chrono::steady_clock::now() - m_last_run_time_stamp[network_group_handle]));
+
+ for (auto &name_counter_pair : m_written_buffer[network_group_handle]) {
+ // Check if there arent any write requests
+ if (0 == name_counter_pair.second) {
+ return false;
+ }
+
+ // Check if there arent enough write requests and timeout didnt passed
+ if ((name_counter_pair.second < m_min_threshold_per_stream[network_group_handle][name_counter_pair.first]) && (!timeout_passed)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+hailo_status NetworkGroupScheduler::wait_for_read(const network_group_handle_t &network_group_handle, const std::string &stream_name)
+{
+ {
+ std::unique_lock<std::mutex> lock(m_before_read_write_mutex);
+ assert(contains(m_allowed_read, network_group_handle));
+ assert(contains(m_allowed_read[network_group_handle], stream_name));
+
+ hailo_status status = HAILO_UNINITIALIZED;
+ m_write_read_cv.wait(lock, [this, network_group_handle, stream_name, &status, &lock] {
+ assert(contains(m_should_ng_stop, network_group_handle));
+ if (m_should_ng_stop[network_group_handle][stream_name]) {
+ status = HAILO_STREAM_INTERNAL_ABORT;
+ return true; // return true so that the wait will finish
+ }
+
+ status = switch_network_group_if_idle(network_group_handle, lock);
+ if (HAILO_SUCCESS != status) {
+ return true; // return true so that the wait will finish
+ }
+
+ status = switch_network_group_if_should_be_next(network_group_handle, lock);
+ if (HAILO_SUCCESS != status) {
+ return true; // return true so that the wait will finish
+ }
+
+ return can_stream_read(network_group_handle, stream_name);
+ });
+ if (HAILO_STREAM_INTERNAL_ABORT == status) {
+ return status;
+ }
+ CHECK_SUCCESS(status);
+
+ assert(contains(m_allowed_read, network_group_handle));
+ m_allowed_read[network_group_handle][stream_name]++;
+ }
+ m_write_read_cv.notify_all();
+
+ return HAILO_SUCCESS;
+}
+
+bool NetworkGroupScheduler::can_stream_read(const network_group_handle_t &network_group_handle, const std::string &stream_name)
+{
+ if (nullptr == m_ang) {
+ return false;
+ }
+
+ if (m_current_network_group != network_group_handle) {
+ return false;
+ }
+
+ if (m_has_current_ng_finished) {
+ return false;
+ }
+
+ assert(contains(m_allowed_read, network_group_handle));
+ assert(contains(m_sent_pending_buffer, network_group_handle));
+ return m_allowed_read[network_group_handle][stream_name].load() < get_max_value_of_unordered_map(m_sent_pending_buffer[network_group_handle]);
+}
+
+hailo_status NetworkGroupScheduler::signal_read_finish(const network_group_handle_t &network_group_handle, const std::string &stream_name)
+{
+ {
+ std::unique_lock<std::mutex> lock(m_before_read_write_mutex);
+ assert(contains(m_finished_read, network_group_handle));
+ assert(contains(m_finished_read[network_group_handle], stream_name));
+
+ m_finished_read[network_group_handle][stream_name]++;
+ hailo_status status = mark_switching_ng_if_ready();
+ CHECK_SUCCESS(status);
+ }
+ m_write_read_cv.notify_all();
+
+ return HAILO_SUCCESS;
+}
+
+hailo_status NetworkGroupScheduler::mark_switching_ng_if_ready()
+{
+ if (!m_switching_network_group) {
+ for (uint32_t i = 0; i < m_cngs.size() - 1; i++) {
+ network_group_handle_t handle = m_current_network_group + i + 1;
+ handle %= static_cast<uint32_t>(m_cngs.size());
+
+ if (is_network_group_ready(handle)) {
+ m_switching_network_group = true;
+ m_next_network_group = handle;
+ break;
+ }
+ }
+ }
+ m_has_current_ng_finished = has_current_ng_finished();
+
+ // Prevents integer overflow of the counters
+ decrease_current_ng_counters();
+
+ return HAILO_SUCCESS;
+}
+
+bool NetworkGroupScheduler::has_current_ng_finished()
+{
+ uint32_t written_frames = get_max_value_of_unordered_map(m_requested_write[m_current_network_group]);
+ for (auto &name_counter_pair : m_finished_read[m_current_network_group]) {
+ if (name_counter_pair.second < written_frames) {
+ return false;
+ }
+ }
+ for (auto &name_counter_pair : m_finished_sent_pending_buffer[m_current_network_group]) {
+ if (name_counter_pair.second < written_frames) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void NetworkGroupScheduler::reset_current_ng_counters()
+{
+ uint32_t written_frames = get_max_value_of_unordered_map(m_sent_pending_buffer[m_current_network_group]);
+
+ for (auto &name_counter_pair : m_requested_write[m_current_network_group]) {
+ name_counter_pair.second -= written_frames;
+ }
+ for (auto &name_counter_pair : m_written_buffer[m_current_network_group]) {
+ assert(name_counter_pair.second == written_frames);
+ name_counter_pair.second = 0;
+ }
+ for (auto &name_counter_pair : m_sent_pending_buffer[m_current_network_group]) {
+ assert(name_counter_pair.second == written_frames);
+ name_counter_pair.second = 0;
+ }
+ for (auto &name_counter_pair : m_finished_sent_pending_buffer[m_current_network_group]) {
+ assert(name_counter_pair.second == written_frames);
+ name_counter_pair.second = 0;
+ }
+ for (auto &name_counter_pair : m_allowed_read[m_current_network_group]) {
+ // TODO (HRT-6811): Recover from timeout, verify counters
+ name_counter_pair.second = 0;
+ }
+ for (auto &name_counter_pair : m_finished_read[m_current_network_group]) {
+ // TODO (HRT-6811): Recover from timeout, verify counters
+ name_counter_pair.second = 0;
+ }
+}
+
+void NetworkGroupScheduler::decrease_current_ng_counters()
+{
+ if (nullptr == m_ang) {
+ return;
+ }
+
+ // Decrease only if counter is 2 or bigger because reaching 0 can cause states to change
+ for (auto &name_counter_pair : m_requested_write[m_current_network_group]) {
+ if (name_counter_pair.second <= 1) {
+ return;
+ }
+ }
+ for (auto &name_counter_pair : m_written_buffer[m_current_network_group]) {
+ if (name_counter_pair.second <= 1) {
+ return;
+ }
+ }
+ for (auto &name_counter_pair : m_sent_pending_buffer[m_current_network_group]) {
+ if (name_counter_pair.second <= 1) {
+ return;
+ }
+ }
+ for (auto &name_counter_pair : m_finished_sent_pending_buffer[m_current_network_group]) {
+ if (name_counter_pair.second <= 1) {
+ return;
+ }
+ }
+ for (auto &name_counter_pair : m_allowed_read[m_current_network_group]) {
+ if (name_counter_pair.second <= 1) {
+ return;
+ }
+ }
+ for (auto &name_counter_pair : m_finished_read[m_current_network_group]) {
+ if (name_counter_pair.second <= 1) {
+ return;
+ }
+ }
+
+ for (auto &name_counter_pair : m_requested_write[m_current_network_group]) {
+ name_counter_pair.second--;
+ }
+ for (auto &name_counter_pair : m_written_buffer[m_current_network_group]) {
+ name_counter_pair.second--;
+ }
+ for (auto &name_counter_pair : m_sent_pending_buffer[m_current_network_group]) {
+ name_counter_pair.second--;
+ }
+ for (auto &name_counter_pair : m_finished_sent_pending_buffer[m_current_network_group]) {
+ name_counter_pair.second--;
+ }
+ for (auto &name_counter_pair : m_allowed_read[m_current_network_group]) {
+ name_counter_pair.second--;
+ }
+ for (auto &name_counter_pair : m_finished_read[m_current_network_group]) {
+ name_counter_pair.second--;
+ }
+}
+
+hailo_status NetworkGroupScheduler::enable_stream(const network_group_handle_t &network_group_handle, const std::string &stream_name)
+{
+ {
+ std::unique_lock<std::mutex> lock(m_before_read_write_mutex);
+
+ assert(contains(m_should_ng_stop, network_group_handle));
+ if (!m_should_ng_stop[network_group_handle][stream_name]) {
+ return HAILO_SUCCESS;
+ }
+
+ m_should_ng_stop[network_group_handle][stream_name] = false;
+ }
+ m_write_read_cv.notify_all();
+ return HAILO_SUCCESS;
+}
+
+hailo_status NetworkGroupScheduler::disable_stream(const network_group_handle_t &network_group_handle, const std::string &stream_name)
+{
+ {
+ std::unique_lock<std::mutex> lock(m_before_read_write_mutex);
+
+ assert(contains(m_should_ng_stop, network_group_handle));
+ if (m_should_ng_stop[network_group_handle][stream_name]) {
+ return HAILO_SUCCESS;
+ }
+
+ m_should_ng_stop[network_group_handle][stream_name] = true;
+
+ // Signal event to exit infinite timeout on wait_for_write if actually an input stream
+ assert(contains(m_write_buffer_events, network_group_handle));
+ if (contains(m_write_buffer_events[network_group_handle], stream_name)) {
+ auto status = m_write_buffer_events[network_group_handle][stream_name]->signal();
+ CHECK_SUCCESS(status);
+ }
+ }
+ m_write_read_cv.notify_all();
+ return HAILO_SUCCESS;
+}
+
+hailo_status NetworkGroupScheduler::set_timeout(const network_group_handle_t &network_group_handle, const std::chrono::milliseconds &timeout, const std::string &network_name)
+{
+ (void)network_name;
+
+ assert(contains(m_timeout_per_network_group, network_group_handle));
+ assert(contains(m_last_run_time_stamp, network_group_handle));
+ CHECK((std::chrono::time_point<std::chrono::steady_clock>() == m_last_run_time_stamp[network_group_handle]), HAILO_INVALID_OPERATION,
+ "Setting scheduler timeout is allowed only before sending / receiving frames on the network group.");
+ m_timeout_per_network_group[network_group_handle] = timeout;
+
+ assert(m_cngs.size() > network_group_handle);
+ auto cng = m_cngs[network_group_handle].lock();
+ CHECK(cng, HAILO_INTERNAL_FAILURE);
+
+ auto name = (network_name.empty()) ? cng->get_network_group_name() : network_name;
+ LOGGER__INFO("Setting scheduler timeout of {} to {}ms", name, timeout.count());
+
+ return HAILO_SUCCESS;
+}
+
+hailo_status NetworkGroupScheduler::set_threshold(const network_group_handle_t &network_group_handle, uint32_t threshold, const std::string &network_name)
+{
+ (void)network_name;
+
+ assert(contains(m_min_threshold_per_stream, network_group_handle));
+ assert(contains(m_last_run_time_stamp, network_group_handle));
+ CHECK((std::chrono::time_point<std::chrono::steady_clock>() == m_last_run_time_stamp[network_group_handle]), HAILO_INVALID_OPERATION,
+ "Setting scheduler threshold is allowed only before sending / receiving frames on the network group.");
+ for (auto &threshold_per_stream_pair : m_min_threshold_per_stream[network_group_handle]) {
+ threshold_per_stream_pair.second = threshold;
+ }
+
+ assert(m_cngs.size() > network_group_handle);
+ auto cng = m_cngs[network_group_handle].lock();
+ CHECK(cng, HAILO_INTERNAL_FAILURE);
+
+ auto name = (network_name.empty()) ? cng->get_network_group_name() : network_name;
+ LOGGER__INFO("Setting scheduler threshold of {} to {} frames", name, threshold);
+
+ return HAILO_SUCCESS;
+}
+
+} /* namespace hailort */
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file network_group_scheduler.hpp
+ * @brief Class declaration for NetworkGroupScheduler that schedules network groups to be active depending on the scheduling algorithm.
+ **/
+
+#ifndef _HAILO_NETWORK_GROUP_SCHEDULER_HPP_
+#define _HAILO_NETWORK_GROUP_SCHEDULER_HPP_
+
+#include "hailo/hailort.h"
+#include "hailo/expected.hpp"
+#include "common/utils.hpp"
+#include "hailo/network_group.hpp"
+
+#include <condition_variable>
+
+#define DEFAULT_SCHEDULER_TIMEOUT (std::chrono::milliseconds(0))
+#define DEFAULT_SCHEDULER_MIN_THRESHOLD (1)
+
+namespace hailort
+{
+
+#define INVALID_NETWORK_GROUP_HANDLE (UINT32_MAX)
+using network_group_handle_t = uint32_t;
+
+const auto SCHEDULER_REFRESH_INTERVAL = std::chrono::milliseconds(500);
+
+class NetworkGroupScheduler;
+using NetworkGroupSchedulerPtr = std::shared_ptr<NetworkGroupScheduler>;
+
+// We use mostly weak pointer for the scheduler to prevent circular dependency of the pointers
+using NetworkGroupSchedulerWeakPtr = std::weak_ptr<NetworkGroupScheduler>;
+
+using stream_name_t = std::string;
+class NetworkGroupScheduler final {
+public:
+ static Expected<NetworkGroupSchedulerPtr> create_shared(hailo_scheduling_algorithm_t algorithm);
+ NetworkGroupScheduler(hailo_scheduling_algorithm_t algorithm)
+ : m_algorithm(algorithm), m_before_read_write_mutex(), m_write_read_cv(), m_current_network_group(0),
+ m_switching_network_group(true), m_has_current_ng_finished(true), m_next_network_group(0), m_forced_idle_state(false)
+ {
+ // Temp solution until we'll implement timeout as timers
+ m_thread = std::thread([this] () {
+ while (!m_should_stop.load()) {
+ m_write_read_cv.notify_all();
+ std::this_thread::sleep_for(SCHEDULER_REFRESH_INTERVAL);
+ }
+ });
+ }
+
+ ~NetworkGroupScheduler()
+ {
+ m_should_stop = true;
+ m_thread.join();
+ }
+
+ hailo_scheduling_algorithm_t algorithm()
+ {
+ return m_algorithm;
+ }
+
+ Expected<network_group_handle_t> add_network_group(std::weak_ptr<ConfiguredNetworkGroup> added_cng);
+
+ hailo_status wait_for_write(const network_group_handle_t &network_group_handle, const std::string &stream_name);
+ hailo_status signal_write_finish(const network_group_handle_t &network_group_handle, const std::string &stream_name);
+ hailo_status wait_for_read(const network_group_handle_t &network_group_handle, const std::string &stream_name);
+ hailo_status signal_read_finish(const network_group_handle_t &network_group_handle, const std::string &stream_name);
+
+ hailo_status enable_stream(const network_group_handle_t &network_group_handle, const std::string &stream_name);
+ hailo_status disable_stream(const network_group_handle_t &network_group_handle, const std::string &stream_name);
+
+ hailo_status set_timeout(const network_group_handle_t &network_group_handle, const std::chrono::milliseconds &timeout, const std::string &network_name);
+ hailo_status set_threshold(const network_group_handle_t &network_group_handle, uint32_t threshold, const std::string &network_name);
+
+ class SchedulerIdleGuard final {
+ /* After 'set_scheduler()' is called, the idle guard will guarantee nothing is running on the device.
+ Relevant for state and configs changes */
+ public:
+ SchedulerIdleGuard() = default;
+ ~SchedulerIdleGuard();
+ hailo_status set_scheduler(std::shared_ptr<NetworkGroupScheduler> scheduler);
+ private:
+ std::shared_ptr<NetworkGroupScheduler> m_scheduler;
+ };
+
+ static std::unique_ptr<SchedulerIdleGuard> create_scheduler_idle_guard()
+ {
+ auto guard = make_unique_nothrow<SchedulerIdleGuard>();
+ return guard;
+ }
+
+private:
+ hailo_status switch_network_group_if_idle(const network_group_handle_t &network_group_handle, std::unique_lock<std::mutex> &read_write_lock);
+ hailo_status activate_network_group(const network_group_handle_t &network_group_handle, std::unique_lock<std::mutex> &read_write_lock);
+ hailo_status send_all_pending_buffers(const network_group_handle_t &network_group_handle, std::unique_lock<std::mutex> &read_write_lock);
+ hailo_status send_pending_buffer(const network_group_handle_t &network_group_handle, const std::string &stream_name, std::unique_lock<std::mutex> &read_write_lock);
+ hailo_status switch_network_group_if_should_be_next(const network_group_handle_t &network_group_handle, std::unique_lock<std::mutex> &read_write_lock);
+ void deactivate_network_group();
+ bool is_network_group_ready(const network_group_handle_t &network_group_handle);
+ hailo_status mark_switching_ng_if_ready();
+ bool can_stream_read(const network_group_handle_t &network_group_handle, const std::string &stream_name);
+ bool has_current_ng_finished();
+ void reset_current_ng_counters();
+ void decrease_current_ng_counters();
+ hailo_status allow_all_writes();
+ hailo_status allow_writes_for_other_inputs_if_needed(const network_group_handle_t &network_group_handle);
+
+ void force_idle_state();
+ void resume_from_idle_state();
+
+ hailo_scheduling_algorithm_t m_algorithm;
+ std::mutex m_before_read_write_mutex;
+ std::condition_variable m_write_read_cv;
+ std::unordered_map<network_group_handle_t, std::unordered_map<stream_name_t, std::atomic_bool>> m_should_ng_stop;
+ std::unordered_map<network_group_handle_t, std::unordered_map<stream_name_t, std::atomic_uint32_t>> m_requested_write;
+ std::unordered_map<network_group_handle_t, std::unordered_map<stream_name_t, std::atomic_uint32_t>> m_written_buffer;
+ std::unordered_map<network_group_handle_t, std::unordered_map<stream_name_t, EventPtr>> m_write_buffer_events;
+ std::unordered_map<network_group_handle_t, std::unordered_map<stream_name_t, std::atomic_uint32_t>> m_sent_pending_buffer;
+ std::unordered_map<network_group_handle_t, std::unordered_map<stream_name_t, std::atomic_uint32_t>> m_finished_sent_pending_buffer;
+ std::unordered_map<network_group_handle_t, std::unordered_map<stream_name_t, std::atomic_uint32_t>> m_allowed_read;
+ std::unordered_map<network_group_handle_t, std::unordered_map<stream_name_t, std::atomic_uint32_t>> m_finished_read;
+ network_group_handle_t m_current_network_group;
+ std::vector<std::weak_ptr<ConfiguredNetworkGroup>> m_cngs;
+ std::unique_ptr<ActivatedNetworkGroup> m_ang;
+ std::atomic_bool m_switching_network_group;
+ std::atomic_bool m_has_current_ng_finished;
+ network_group_handle_t m_next_network_group;
+ std::atomic_bool m_forced_idle_state;
+
+ std::thread m_thread;
+ std::atomic_bool m_should_stop;
+
+ std::unordered_map<network_group_handle_t, std::unordered_map<stream_name_t, std::atomic_uint32_t>> m_min_threshold_per_stream;
+ std::unordered_map<network_group_handle_t, std::chrono::milliseconds> m_timeout_per_network_group;
+ std::unordered_map<network_group_handle_t, std::chrono::time_point<std::chrono::steady_clock>> m_last_run_time_stamp;
+};
+
+} /* namespace hailort */
+
+#endif /* _HAILO_NETWORK_GROUP_SCHEDULER_HPP_ */
${HAILO_FULL_OS_DIR}/event.cpp
)
-if(UNIX)
+if(CMAKE_SYSTEM_NAME STREQUAL QNX)
+ # QNX only modules
+ set(files ${files}
+ ${HAILO_OS_DIR}/qnx/pcie_driver_scan.cpp
+ )
+elseif(UNIX)
# Unix only modules
set(files ${files}
- ${HAILO_OS_DIR}/pcie_driver_sysfs.cpp
+ ${HAILO_OS_DIR}/unix/pcie_driver_scan.cpp
)
endif()
// When measuring latency, each channel is capable of PENDING_BUFFERS_SIZE active transfers, each transfer raises max of 2 timestamps
#define MAX_IRQ_TIMESTAMPS_SIZE (PENDING_BUFFERS_SIZE * 2)
+#define DESCRIPTORS_IN_BUFFER(buffer_size, desc_page_size) (((buffer_size) + (desc_page_size) - 1) / (desc_page_size))
+
#define PCIE_EXPECTED_MD5_LENGTH (16)
enum class PciBar {
* Frees a vdma descriptors buffer allocated by 'create_descriptors_buffer'.
*/
hailo_status descriptors_list_release(uintptr_t desc_handle);
-
- Expected<uintptr_t> vdma_low_memory_buffer_alloc(size_t size);
- hailo_status vdma_low_memory_buffer_free(uintptr_t buffer_handle);
/**
* Configure vdma channel descriptors to point to the given user address.
hailo_status descriptors_list_bind_vdma_buffer(uintptr_t desc_handle, VdmaBufferHandle buffer_handle,
uint16_t desc_page_size, uint8_t channel_index);
+ Expected<uintptr_t> vdma_low_memory_buffer_alloc(size_t size);
+ hailo_status vdma_low_memory_buffer_free(uintptr_t buffer_handle);
+
+ /**
+ * Allocate continuous vdma buffer.
+ *
+ * @param[in] size - Buffer size
+ * @return pair <buffer_handle, dma_address>.
+ */
+ Expected<std::pair<uintptr_t, uint64_t>> vdma_continuous_buffer_alloc(size_t size);
+
+ /**
+ * Frees a vdma continuous buffer allocated by 'vdma_continuous_buffer_alloc'.
+ */
+ hailo_status vdma_continuous_buffer_free(uintptr_t buffer_handle);
+
/**
* The actual desc page size might be smaller than the once requested, depends on the host capabilities.
*/
#include "os/hailort_driver.hpp"
-#include "os/posix/pcie_driver_sysfs.hpp"
+#include "os/posix/pcie_driver_scan.hpp"
#include "hailo_ioctl_common.h"
#include "common/logger_macros.hpp"
#include "common/utils.hpp"
return HAILO_SUCCESS;
}
+#if defined(__linux__)
Expected<std::vector<HailoRTDriver::DeviceInfo>> HailoRTDriver::scan_pci()
{
- auto device_names = list_sysfs_pcie_devices();
+ auto device_names = list_pcie_devices();
CHECK_EXPECTED(device_names, "Failed listing pcie devices");
std::vector<HailoRTDriver::DeviceInfo> devices_info;
}
return devices_info;
}
+#elif defined(__QNX__)
+Expected<std::vector<HailoRTDriver::DeviceInfo>> HailoRTDriver::scan_pci()
+{
+ auto device_names = list_pcie_devices();
+ CHECK_EXPECTED(device_names, "Failed listing pcie devices");
+
+ // TODO: HRT-6785 - support multiple devices - currently device_names is vector of one device - in future will be multiple
+ std::vector<HailoRTDriver::DeviceInfo> devices_info;
+ uint32_t index = 0;
+ for (const auto &device_name : device_names.value()) {
+ auto device_info = query_device_info(device_name, index);
+ CHECK_EXPECTED(device_info, "failed parsing device info for {}", device_name);
+ devices_info.push_back(device_info.release());
+ index++;
+ }
+ return devices_info;
+}
+#else
+static_assert(true, "Error, Unsupported Platform");
+#endif //defined (__linux__)
Expected<uint32_t> HailoRTDriver::read_vdma_channel_registers(off_t offset, size_t size)
{
.bar_index = static_cast<uint32_t>(bar),
.offset = offset,
.count = size,
- .buffer = buf
+ .buffer = {0}
};
+ if (size > sizeof(transfer.buffer)) {
+ LOGGER__ERROR("Invalid size to read, size given {} is larger than max size {}", size, sizeof(transfer.buffer));
+ return HAILO_INVALID_ARGUMENT;
+ }
+
if (0 > ioctl(this->m_fd, HAILO_BAR_TRANSFER, &transfer)) {
LOGGER__ERROR("HailoRTDriver::read_bar failed with errno:{}", errno);
return HAILO_PCIE_DRIVER_FAIL;
}
+ memcpy(buf, transfer.buffer, transfer.count);
+
return HAILO_SUCCESS;
}
.bar_index = static_cast<uint32_t>(bar),
.offset = offset,
.count = size,
- .buffer = (void*)buf
+ .buffer = {0}
};
+ if (size > sizeof(transfer.buffer)) {
+ LOGGER__ERROR("Invalid size to read, size given {} is larger than max size {}", size, sizeof(transfer.buffer));
+ return HAILO_INVALID_ARGUMENT;
+ }
+
+ memcpy(transfer.buffer, buf, transfer.count);
+
if (0 > ioctl(this->m_fd, HAILO_BAR_TRANSFER, &transfer)) {
LOGGER__ERROR("HailoRTDriver::write_bar failed with errno:{}", errno);
return HAILO_PCIE_DRIVER_FAIL;
hailo_read_log_params params {
.cpu_id = translate_cpu_id(cpu_id),
- .buffer = buffer,
+ .buffer = {0},
.buffer_size = buffer_size,
.read_bytes = 0
};
+ CHECK(buffer_size <= sizeof(params.buffer), HAILO_PCIE_DRIVER_FAIL,
+ "Given buffer size {} is bigger than buffer size used to read logs {}", buffer_size, sizeof(params.buffer));
+
if (0 > ioctl(this->m_fd, HAILO_READ_LOG, ¶ms)) {
LOGGER__ERROR("Failed to read log with errno:{}", errno);
return HAILO_PCIE_DRIVER_FAIL;
}
+ CHECK(params.read_bytes <= sizeof(params.buffer), HAILO_PCIE_DRIVER_FAIL,
+ "Amount of bytes read from log {} is bigger than size of buffer {}", params.read_bytes, sizeof(params.buffer));
+
+ memcpy(buffer, params.buffer, params.read_bytes);
*read_bytes = params.read_bytes;
return HAILO_SUCCESS;
CHECK_AS_EXPECTED(m_allocate_driver_buffer, HAILO_INVALID_OPERATION,
"Tried to allocate buffer from driver even though operation is not supported");
- hailo_allocate_buffer_params allocate_params = {
+ hailo_allocate_low_memory_buffer_params allocate_params = {
.buffer_size = size,
.buffer_handle = 0
};
return HAILO_SUCCESS;
}
+Expected<std::pair<uintptr_t, uint64_t>> HailoRTDriver::vdma_continuous_buffer_alloc(size_t size)
+{
+ hailo_allocate_continuous_buffer_params params { .buffer_size = size, .buffer_handle = 0, .dma_address = 0 };
+
+ if (0 > ioctl(this->m_fd, HAILO_VDMA_CONTINUOUS_BUFFER_ALLOC, ¶ms)) {
+ LOGGER__ERROR("Failed allocate continuous buffer with errno:{}", errno);
+ return make_unexpected(HAILO_PCIE_DRIVER_FAIL);
+ }
+
+ return std::make_pair(params.buffer_handle, params.dma_address);
+}
+
+hailo_status HailoRTDriver::vdma_continuous_buffer_free(uintptr_t buffer_handle)
+{
+ if (0 > ioctl(this->m_fd, HAILO_VDMA_CONTINUOUS_BUFFER_FREE, buffer_handle)) {
+ LOGGER__ERROR("Failed to free continuous buffer with errno: {}", errno);
+ return HAILO_PCIE_DRIVER_FAIL;
+ }
+
+ return HAILO_SUCCESS;
+}
+
hailo_status HailoRTDriver::mark_as_used()
{
hailo_mark_as_in_use_params params = {
#include <sys/mman.h>
#include <errno.h>
-#if defined(__unix__)
+#if defined(__linux__)
#include <linux/mman.h>
#endif
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file pcie_driver_scan.hpp
+ * @brief Get list and parse pcie driver info
+ **/
+
+#include "os/hailort_driver.hpp"
+
+namespace hailort
+{
+
+Expected<std::vector<std::string>> list_pcie_devices();
+#if defined(__linux__)
+Expected<HailoRTDriver::DeviceInfo> query_device_info(const std::string &device_name);
+#elif defined(__QNX__)
+Expected<HailoRTDriver::DeviceInfo> query_device_info(const std::string &device_name, uint32_t index);
+#endif // defined(__linux__)
+
+} /* namespace hailort */
+++ /dev/null
-/**
- * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
- * Distributed under the MIT license (https://opensource.org/licenses/MIT)
- **/
-/**
- * @file pcie_driver_sysfs.cpp
- * @brief Parse pcie driver sysfs
- **/
-
-#include "os/posix/pcie_driver_sysfs.hpp"
-#include <stdarg.h>
-#include <dirent.h>
-
-namespace hailort
-{
-
-#define HAILO_PCIE_CLASS_PATH ("/sys/class/hailo_chardev")
-#define HAILO_BOARD_LOCATION_FILENAME ("board_location")
-#define HAILO_DEVICE_ID_FILENAME ("device_id")
-
-
-Expected<std::vector<std::string>> list_sysfs_pcie_devices()
-{
- DIR *dir_iter = opendir(HAILO_PCIE_CLASS_PATH);
- if (!dir_iter) {
- if (ENOENT == errno) {
- LOGGER__ERROR("Can't find hailo pcie class, this may happen if the driver is not installed (this may happen"
- " if the kernel was updated), or if there is no connected Hailo board");
- return make_unexpected(HAILO_PCIE_DRIVER_NOT_INSTALLED);
- }
- else {
- LOGGER__ERROR("Failed to open hailo pcie class ({}), errno {}", HAILO_PCIE_CLASS_PATH, errno);
- return make_unexpected(HAILO_PCIE_DRIVER_FAIL);
- }
- }
-
- std::vector<std::string> devices;
- struct dirent *dir = nullptr;
- while ((dir = readdir(dir_iter)) != nullptr) {
- std::string device_name(dir->d_name);
- if (device_name == "." || device_name == "..") {
- continue;
- }
- devices.push_back(device_name);
- }
-
- closedir(dir_iter);
- return devices;
-}
-
-/**
- * Parses hailo driver sysfs entry using scanf format string
- * @param device_name - name of the specific device (inside hailo class sysfs directory)
- * @param sysfs_file_name - file name inside the device sysfs directory
- * @param expected_count - expected amount of scanf variable
- * @param fscanf_format - scanf format of the file
- * @param ... - external arguments, filled by the scanf
- */
-__attribute__((__format__ (__scanf__, 4, 5)))
-static hailo_status parse_device_sysfs_file(const std::string &device_name, const std::string &sysfs_file_name, uint32_t expected_count,
- const char *fscanf_format, ...)
-{
- std::string sysfs_file_path = std::string(HAILO_PCIE_CLASS_PATH) + "/" +
- device_name + "/" + sysfs_file_name;
- FILE *file_obj = fopen(sysfs_file_path.c_str(), "r");
- if (!file_obj) {
- LOGGER__ERROR("Failed opening sysfs file {}, errno {}", sysfs_file_path, errno);
- return HAILO_FILE_OPERATION_FAILURE;
- }
-
- va_list args;
- va_start(args, fscanf_format);
- auto items_count = vfscanf(file_obj, fscanf_format, args);
- va_end(args);
- fclose(file_obj);
-
- if (static_cast<uint32_t>(items_count) != expected_count) {
- LOGGER__ERROR("Invalid sysfs file format {}", sysfs_file_path);
- return HAILO_PCIE_DRIVER_FAIL;
- }
-
- return HAILO_SUCCESS;
-}
-
-Expected<HailoRTDriver::DeviceInfo> query_device_info(const std::string &device_name)
-{
- HailoRTDriver::DeviceInfo device_info = {};
- device_info.dev_path = std::string("/dev/") + device_name;
-
- auto status = parse_device_sysfs_file(device_name, HAILO_BOARD_LOCATION_FILENAME, 4, "%04x:%02x:%02x.%d",
- &device_info.domain, &device_info.bus, &device_info.device, &device_info.func);
- CHECK_SUCCESS_AS_EXPECTED(status, "Failed reading {} file", HAILO_BOARD_LOCATION_FILENAME);
-
- status = parse_device_sysfs_file(device_name, HAILO_DEVICE_ID_FILENAME, 2, "%x:%x",
- &device_info.vendor_id, &device_info.device_id);
- CHECK_SUCCESS_AS_EXPECTED(status, "Failed reading {} file", HAILO_DEVICE_ID_FILENAME);
-
- return device_info;
-}
-
-} /* namespace hailort */
+++ /dev/null
-/**
- * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
- * Distributed under the MIT license (https://opensource.org/licenses/MIT)
- **/
-/**
- * @file pcie_driver_sysfs.hpp
- * @brief Parse pcie driver sysfs
- **/
-
-#include "os/hailort_driver.hpp"
-
-namespace hailort
-{
-
-Expected<std::vector<std::string>> list_sysfs_pcie_devices();
-Expected<HailoRTDriver::DeviceInfo> query_device_info(const std::string &device_name);
-
-} /* namespace hailort */
* @file event.cpp
* @brief Event & Semaphore wrapper for QNX
*
- * TODO: doc
+ * This class implements our Events API over the neosmart pevents events. It also implement the Semaphore behavior and API
+ * Using the pevents events. For more information check out the implementation of pevents https://github.com/neosmart/pevents
**/
#include "hailo/event.hpp"
#include "hailo/hailort.h"
#include <poll.h>
#include <utility>
-#define INVALID_FD (-1)
+#define WFMO
+#include "pevents.h"
+#undef WFMO
+
+#define INVALID_EVENT_HANDLE (nullptr)
+#define WAIT_OBJECT_0 (0)
namespace hailort
{
-Waitable::Waitable(underlying_handle_t handle) :
+Waitable::Waitable(underlying_waitable_handle_t handle) :
m_handle(handle)
{}
Waitable::~Waitable()
{
- if (-1 != m_handle) {
- (void) close(m_handle);
+ if (INVALID_EVENT_HANDLE != m_handle) {
+ int err = 0;
+ if (0 != (err = neosmart::DestroyEvent(m_handle))) {
+ LOGGER__ERROR("Error destroying event handle, returned error={}", err);
+ }
}
}
Waitable::Waitable(Waitable&& other) :
- m_handle(std::exchange(other.m_handle, INVALID_FD))
+ m_handle(std::exchange(other.m_handle, INVALID_EVENT_HANDLE))
{}
-underlying_handle_t Waitable::get_underlying_handle()
+underlying_waitable_handle_t Waitable::get_underlying_handle()
{
return m_handle;
}
-hailo_status Waitable::eventfd_poll(underlying_handle_t fd, std::chrono::milliseconds timeout)
-{
- (void) fd;
- (void) timeout;
- return HAILO_NOT_IMPLEMENTED;
-}
-
-hailo_status Waitable::eventfd_read(underlying_handle_t fd)
+hailo_status Waitable::wait_for_single_object(underlying_waitable_handle_t handle, std::chrono::milliseconds timeout)
{
- (void) fd;
- return HAILO_NOT_IMPLEMENTED;
-}
-
-hailo_status Waitable::eventfd_write(underlying_handle_t fd)
-{
- (void) fd;
- return HAILO_NOT_IMPLEMENTED;
+ const size_t timeout_ms = (timeout.count() > INT_MAX) ? INT_MAX : static_cast<size_t>(timeout.count());
+ const auto wait_result = neosmart::WaitForEvent(handle, timeout_ms);
+ switch (wait_result) {
+ case WAIT_OBJECT_0:
+ return HAILO_SUCCESS;
+ case ETIMEDOUT:
+ return HAILO_TIMEOUT;
+ default:
+ LOGGER__ERROR("WaitForEvent failed, returned error={}", wait_result);
+ return HAILO_INTERNAL_FAILURE;
+ }
}
Expected<Event> Event::create(const State& initial_state)
{
- (void) initial_state;
- return make_unexpected(HAILO_NOT_IMPLEMENTED);
+ const auto handle = open_event_handle(initial_state);
+ if (INVALID_EVENT_HANDLE == handle) {
+ return make_unexpected(HAILO_INTERNAL_FAILURE);
+ }
+ return std::move(Event(handle));
}
EventPtr Event::create_shared(const State& initial_state)
{
- (void) initial_state;
- return make_shared_nothrow<Event>(INVALID_FD);
+ const auto handle = open_event_handle(initial_state);
+ if (INVALID_EVENT_HANDLE == handle) {
+ return nullptr;
+ }
+
+ return make_shared_nothrow<Event>(handle);
}
hailo_status Event::wait(std::chrono::milliseconds timeout)
{
- (void) timeout;
- return HAILO_NOT_IMPLEMENTED;
+ return wait_for_single_object(m_handle, timeout);
}
hailo_status Event::signal()
{
- return HAILO_NOT_IMPLEMENTED;
+ const auto result = neosmart::SetEvent(m_handle);
+ CHECK(0 != result, HAILO_INTERNAL_FAILURE, "SetEvent failed with error {}" , result);
+
+ return HAILO_SUCCESS;
}
bool Event::is_auto_reset()
hailo_status Event::reset()
{
- return HAILO_NOT_IMPLEMENTED;
+ const auto result = neosmart::ResetEvent(m_handle);
+ CHECK(0 != result, HAILO_INTERNAL_FAILURE, "ResetEvent failed with error {}", result);
+
+ return HAILO_SUCCESS;
}
-underlying_handle_t Event::open_event_handle(const State& initial_state)
+underlying_waitable_handle_t Event::open_event_handle(const State& initial_state)
{
- (void) initial_state;
- return INVALID_FD;
+ static const auto manual_reset = true;
+ const bool state = (initial_state == State::signalled ? true : false);
+ auto event = neosmart::CreateEvent(manual_reset, state);
+ if (INVALID_EVENT_HANDLE == event) {
+ LOGGER__ERROR("Call to CreateEvent failed");
+ }
+ return event;
}
Expected<Semaphore> Semaphore::create(uint32_t initial_count)
{
- (void) initial_count;
- return make_unexpected(HAILO_NOT_IMPLEMENTED);
+ const auto handle = open_semaphore_handle(initial_count);
+ if (INVALID_EVENT_HANDLE == handle) {
+ return make_unexpected(HAILO_INTERNAL_FAILURE);
+ }
+ return std::move(Semaphore(handle, initial_count));
}
SemaphorePtr Semaphore::create_shared(uint32_t initial_count)
{
- (void) initial_count;
- return make_shared_nothrow<Semaphore>(INVALID_FD);
+ const auto handle = open_semaphore_handle(initial_count);
+ if (INVALID_EVENT_HANDLE == handle) {
+ return nullptr;
+ }
+
+ return make_shared_nothrow<Semaphore>(handle, initial_count);
}
hailo_status Semaphore::wait(std::chrono::milliseconds timeout)
{
- (void) timeout;
- return HAILO_NOT_IMPLEMENTED;
+ auto wait_result = wait_for_single_object(m_handle, timeout);
+ if (HAILO_SUCCESS == wait_result) {
+ m_sem_mutex.lock();
+ if (0 == m_count.load()) {
+ LOGGER__ERROR("Waiting on semaphore with 0 value");
+ }
+ if (m_count > 0) {
+ m_count--;
+ }
+ // After decrementing the value of the semaphore - check if the new value is bigger than 0 and if it is signal the event
+ if (m_count > 0) {
+ neosmart::SetEvent(m_handle);
+ }
+ m_sem_mutex.unlock();
+ }
+
+ return wait_result;
}
hailo_status Semaphore::signal()
{
- return HAILO_NOT_IMPLEMENTED;
+ m_sem_mutex.lock();
+ const auto result = neosmart::SetEvent(m_handle);
+ if (0 != result) {
+ LOGGER__ERROR("SetEvent failed with error {}", result);
+ m_sem_mutex.unlock();
+ return HAILO_INTERNAL_FAILURE;
+ }
+ m_count++;
+ m_sem_mutex.unlock();
+
+ return HAILO_SUCCESS;
}
bool Semaphore::is_auto_reset()
return true;
}
-underlying_handle_t Semaphore::open_semaphore_handle(uint32_t initial_count)
+underlying_waitable_handle_t Semaphore::open_semaphore_handle(uint32_t initial_count)
{
- (void) initial_count;
- return INVALID_FD;
+ static const auto manual_reset = false;
+ static const auto state = (initial_count > 0 ? true : false);
+ auto event = neosmart::CreateEvent(manual_reset, state);
+ if (INVALID_EVENT_HANDLE == event) {
+ LOGGER__ERROR("Call to CreateEvent failed");
+ }
+ return event;
}
-WaitOrShutdown::WaitOrShutdown(WaitablePtr waitable, EventPtr shutdown_event)
+Semaphore::Semaphore(underlying_waitable_handle_t handle, uint32_t initial_count) :
+ Waitable(handle), m_count(initial_count)
+{}
+
+Semaphore::Semaphore(Semaphore&& other) :
+ Waitable(std::move(other))
{
- (void) waitable;
- (void) shutdown_event;
+ other.m_sem_mutex.lock();
+ m_count.store(other.m_count.load());
+ other.m_sem_mutex.unlock();
+}
+
+WaitOrShutdown::WaitOrShutdown(WaitablePtr waitable, EventPtr shutdown_event) :
+ m_waitable(waitable),
+ m_shutdown_event(shutdown_event),
+ m_wait_handle_array(create_wait_handle_array(waitable, shutdown_event))
+{}
+
+void Event::post_wait()
+{}
+
+void Semaphore::post_wait(){
+ m_sem_mutex.lock();
+ if (0 == m_count.load()) {
+ LOGGER__ERROR("Wait Returned on semaphore with 0 value");
+ }
+ if (m_count > 0) {
+ m_count--;
+ }
+ // After decrementing the value of the semaphore - check if the new value is bigger than 0 and if it is signal the event
+ if (m_count > 0) {
+ neosmart::SetEvent(m_handle);
+ }
+ m_sem_mutex.unlock();
}
hailo_status WaitOrShutdown::wait(std::chrono::milliseconds timeout)
{
- (void) timeout;
- return HAILO_NOT_IMPLEMENTED;
+ int wait_index = -1;
+ const uint64_t timeout_ms = (timeout.count() > INT_MAX) ? INT_MAX : static_cast<uint64_t>(timeout.count());
+ const auto wait_result = neosmart::WaitForMultipleEvents(m_wait_handle_array.data(), static_cast<int>(m_wait_handle_array.size()),
+ false, timeout_ms, wait_index);
+ // If semaphore need to subtract from counter
+ if (0 != wait_result) {
+ if (ETIMEDOUT == wait_result) {
+ return HAILO_TIMEOUT;
+ } else {
+ LOGGER__ERROR("WaitForMultipleEvents Failed, error: {}", wait_result);
+ return HAILO_INTERNAL_FAILURE;
+ }
+ }
+
+ if (WAITABLE_INDEX == wait_index) {
+ // Meaning it can be a semaphore object
+ m_waitable->post_wait();
+ return HAILO_SUCCESS;
+ } else if (SHUTDOWN_INDEX == wait_index) {
+ return HAILO_SHUTDOWN_EVENT_SIGNALED;
+ } else {
+ LOGGER__ERROR("Invalid event index signalled in WaitForMultipleEventsFailed, index: {}", wait_index);
+ return HAILO_INTERNAL_FAILURE;
+ }
}
hailo_status WaitOrShutdown::signal()
{
- return HAILO_NOT_IMPLEMENTED;
+ return m_waitable->signal();
}
WaitOrShutdown::WaitHandleArray WaitOrShutdown::create_wait_handle_array(WaitablePtr waitable, EventPtr shutdown_event)
{
- (void) waitable;
- (void) shutdown_event;
// Note the order!
- WaitHandleArray pfds{{
- {INVALID_FD, POLLIN, 0},
- {INVALID_FD, POLLIN, 0}
- }};
- return pfds;
+ WaitHandleArray handles{
+ shutdown_event->get_underlying_handle(),
+ waitable->get_underlying_handle()
+ };
+ return handles;
}
} /* namespace hailort */
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file pcie_driver_scan.cpp
+ * @brief Get list and parse pcie driver info
+ **/
+
+#include "os/posix/pcie_driver_scan.hpp"
+#include <dirent.h>
+extern "C" {
+#include <pci/pci.h>
+}
+
+namespace hailort
+{
+
+#define HAILO_VENDOR_ID (0x1e60)
+#define HAILO_PCIE_CLASS_PATH ("/dev/")
+// Every device name will start with "hailo"
+#define HAILO_PCIE_DEVICE_NAME_PREFIX ("hailo")
+
+Expected<std::vector<std::string>> list_pcie_devices()
+{
+ DIR *dir_iter = opendir(HAILO_PCIE_CLASS_PATH);
+ if (!dir_iter) {
+ if (ENOENT == errno) {
+ LOGGER__ERROR("Can't find hailo pcie class, this may happen if the driver is not installed (this may happen"
+ " if the kernel was updated), or if there is no connected Hailo board");
+ return make_unexpected(HAILO_PCIE_DRIVER_NOT_INSTALLED);
+ }
+ else {
+ LOGGER__ERROR("Failed to open hailo pcie class ({}), errno {}", HAILO_PCIE_CLASS_PATH, errno);
+ return make_unexpected(HAILO_PCIE_DRIVER_FAIL);
+ }
+ }
+
+ std::vector<std::string> devices;
+ struct dirent *dir = nullptr;
+ while ((dir = readdir(dir_iter)) != nullptr) {
+ std::string device_name(dir->d_name);
+ if (device_name == "." || device_name == "..") {
+ continue;
+ }
+ // Check that it is hailo device
+ if (std::string::npos == device_name.find(HAILO_PCIE_DEVICE_NAME_PREFIX)) {
+ continue;
+ }
+ devices.push_back(device_name);
+ }
+
+ closedir(dir_iter);
+ return devices;
+}
+
+Expected<HailoRTDriver::DeviceInfo> query_device_info(const std::string &device_name, uint32_t index)
+{
+ HailoRTDriver::DeviceInfo dev_info = {};
+ pci_err_t err;
+
+ // pci_device_find finds all relevant devices - find specific using index
+ pci_bdf_t pci_dev = pci_device_find(index, HAILO_VENDOR_ID, PCI_DID_ANY, PCI_CCODE_ANY);
+ if (PCI_BDF_NONE == pci_dev) {
+ LOGGER__ERROR("Error finding relevant device");
+ make_unexpected(HAILO_INVALID_ARGUMENT);
+ }
+
+ pci_did_t device_id;
+ if (PCI_ERR_OK != (err = pci_device_read_did(pci_dev, &device_id))) {
+ LOGGER__ERROR("Failed reading Device ID, error {}", err);
+ make_unexpected(HAILO_INTERNAL_FAILURE);
+ }
+
+ dev_info.dev_path = std::move(std::string(HAILO_PCIE_CLASS_PATH) + device_name);
+ dev_info.vendor_id = HAILO_VENDOR_ID;
+ dev_info.device_id = device_id;
+ dev_info.domain = 0;
+ dev_info.bus = PCI_BUS(pci_dev);
+ dev_info.device = PCI_DEV(pci_dev);
+ dev_info.func = PCI_FUNC(pci_dev);
+
+ return dev_info;
+}
+
+} /* namespace hailort */
namespace hailort
{
-Waitable::Waitable(underlying_handle_t handle) :
+Waitable::Waitable(underlying_waitable_handle_t handle) :
m_handle(handle)
{}
m_handle(std::exchange(other.m_handle, -1))
{}
-underlying_handle_t Waitable::get_underlying_handle()
+underlying_waitable_handle_t Waitable::get_underlying_handle()
{
return m_handle;
}
-hailo_status Waitable::eventfd_poll(underlying_handle_t fd, std::chrono::milliseconds timeout)
+hailo_status Waitable::eventfd_poll(underlying_waitable_handle_t fd, std::chrono::milliseconds timeout)
{
hailo_status status = HAILO_UNINITIALIZED;
struct pollfd pfd{};
return status;
}
-hailo_status Waitable::eventfd_read(underlying_handle_t fd)
+hailo_status Waitable::eventfd_read(underlying_waitable_handle_t fd)
{
hailo_status status = HAILO_UNINITIALIZED;
ssize_t read_ret = -1;
return status;
}
-hailo_status Waitable::eventfd_write(underlying_handle_t fd)
+hailo_status Waitable::eventfd_write(underlying_waitable_handle_t fd)
{
hailo_status status = HAILO_UNINITIALIZED;
ssize_t write_ret = -1;
return eventfd_read(m_handle);
}
-underlying_handle_t Event::open_event_handle(const State& initial_state)
+underlying_waitable_handle_t Event::open_event_handle(const State& initial_state)
{
static const int NO_FLAGS = 0;
const int state = initial_state == State::signalled ? 1 : 0;
return true;
}
-underlying_handle_t Semaphore::open_semaphore_handle(uint32_t initial_count)
+underlying_waitable_handle_t Semaphore::open_semaphore_handle(uint32_t initial_count)
{
static const int SEMAPHORE = EFD_SEMAPHORE;
const auto handle = eventfd(initial_count, SEMAPHORE);
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file pcie_driver_scan.cpp
+ * @brief Parse pcie driver sysfs
+ **/
+
+#include "os/posix/pcie_driver_scan.hpp"
+#include <stdarg.h>
+#include <dirent.h>
+
+namespace hailort
+{
+
+#define HAILO_PCIE_CLASS_PATH ("/sys/class/hailo_chardev")
+#define HAILO_BOARD_LOCATION_FILENAME ("board_location")
+#define HAILO_DEVICE_ID_FILENAME ("device_id")
+
+
+Expected<std::vector<std::string>> list_pcie_devices()
+{
+ DIR *dir_iter = opendir(HAILO_PCIE_CLASS_PATH);
+ if (!dir_iter) {
+ if (ENOENT == errno) {
+ LOGGER__ERROR("Can't find hailo pcie class, this may happen if the driver is not installed (this may happen"
+ " if the kernel was updated), or if there is no connected Hailo board");
+ return make_unexpected(HAILO_PCIE_DRIVER_NOT_INSTALLED);
+ }
+ else {
+ LOGGER__ERROR("Failed to open hailo pcie class ({}), errno {}", HAILO_PCIE_CLASS_PATH, errno);
+ return make_unexpected(HAILO_PCIE_DRIVER_FAIL);
+ }
+ }
+
+ std::vector<std::string> devices;
+ struct dirent *dir = nullptr;
+ while ((dir = readdir(dir_iter)) != nullptr) {
+ std::string device_name(dir->d_name);
+ if (device_name == "." || device_name == "..") {
+ continue;
+ }
+ devices.push_back(device_name);
+ }
+
+ closedir(dir_iter);
+ return devices;
+}
+
+/**
+ * Parses hailo driver sysfs entry using scanf format string
+ * @param device_name - name of the specific device (inside hailo class sysfs directory)
+ * @param sysfs_file_name - file name inside the device sysfs directory
+ * @param expected_count - expected amount of scanf variable
+ * @param fscanf_format - scanf format of the file
+ * @param ... - external arguments, filled by the scanf
+ */
+__attribute__((__format__ (__scanf__, 4, 5)))
+static hailo_status parse_device_sysfs_file(const std::string &device_name, const std::string &sysfs_file_name, uint32_t expected_count,
+ const char *fscanf_format, ...)
+{
+ std::string sysfs_file_path = std::string(HAILO_PCIE_CLASS_PATH) + "/" +
+ device_name + "/" + sysfs_file_name;
+ FILE *file_obj = fopen(sysfs_file_path.c_str(), "r");
+ if (!file_obj) {
+ LOGGER__ERROR("Failed opening sysfs file {}, errno {}", sysfs_file_path, errno);
+ return HAILO_FILE_OPERATION_FAILURE;
+ }
+
+ va_list args;
+ va_start(args, fscanf_format);
+ auto items_count = vfscanf(file_obj, fscanf_format, args);
+ va_end(args);
+ fclose(file_obj);
+
+ if (static_cast<uint32_t>(items_count) != expected_count) {
+ LOGGER__ERROR("Invalid sysfs file format {}", sysfs_file_path);
+ return HAILO_PCIE_DRIVER_FAIL;
+ }
+
+ return HAILO_SUCCESS;
+}
+
+Expected<HailoRTDriver::DeviceInfo> query_device_info(const std::string &device_name)
+{
+ HailoRTDriver::DeviceInfo device_info = {};
+ device_info.dev_path = std::string("/dev/") + device_name;
+
+ auto status = parse_device_sysfs_file(device_name, HAILO_BOARD_LOCATION_FILENAME, 4, "%04x:%02x:%02x.%d",
+ &device_info.domain, &device_info.bus, &device_info.device, &device_info.func);
+ CHECK_SUCCESS_AS_EXPECTED(status, "Failed reading {} file", HAILO_BOARD_LOCATION_FILENAME);
+
+ status = parse_device_sysfs_file(device_name, HAILO_DEVICE_ID_FILENAME, 2, "%x:%x",
+ &device_info.vendor_id, &device_info.device_id);
+ CHECK_SUCCESS_AS_EXPECTED(status, "Failed reading {} file", HAILO_DEVICE_ID_FILENAME);
+
+ return device_info;
+}
+
+} /* namespace hailort */
namespace hailort
{
-Waitable::Waitable(underlying_handle_t handle) :
+Waitable::Waitable(underlying_waitable_handle_t handle) :
m_handle(handle)
{}
m_handle(std::exchange(other.m_handle, nullptr))
{}
-underlying_handle_t Waitable::get_underlying_handle()
+underlying_waitable_handle_t Waitable::get_underlying_handle()
{
return m_handle;
}
return millies;
}
-hailo_status Waitable::wait_for_single_object(underlying_handle_t handle, std::chrono::milliseconds timeout)
+hailo_status Waitable::wait_for_single_object(underlying_waitable_handle_t handle, std::chrono::milliseconds timeout)
{
DWORD wait_millies = timeout_millies(timeout.count());
assert(nullptr != handle);
return HAILO_SUCCESS;
}
-underlying_handle_t Event::open_event_handle(const State& initial_state)
+underlying_waitable_handle_t Event::open_event_handle(const State& initial_state)
{
static const LPSECURITY_ATTRIBUTES NO_INHERITANCE = nullptr;
static const BOOL MANUAL_RESET = true;
return true;
}
-underlying_handle_t Semaphore::open_semaphore_handle(uint32_t initial_count)
+underlying_waitable_handle_t Semaphore::open_semaphore_handle(uint32_t initial_count)
{
static const LPSECURITY_ATTRIBUTES NO_INHERITANCE = nullptr;
static const LONG MAX_SIZE = std::numeric_limits<long>::max();
transfer.bar_index = static_cast<uint32_t>(bar);
transfer.offset = offset;
transfer.count = size;
- transfer.buffer = buf;
+ memset(transfer.buffer, 0, sizeof(transfer.buffer));
+
+ CHECK(size <= sizeof(transfer.buffer), HAILO_INVALID_ARGUMENT,
+ "Invalid size to read, size given {} is larger than max size {}", size, sizeof(transfer.buffer));
if (0 > ioctl(m_fd, HAILO_BAR_TRANSFER, &data)) {
LOGGER__ERROR("HailoRTDriver::read_bar failed with errno:{}", errno);
return HAILO_PCIE_DRIVER_FAIL;
}
+ memcpy(buf, transfer.buffer, transfer.count);
+
return HAILO_SUCCESS;
}
transfer.bar_index = static_cast<uint32_t>(bar);
transfer.offset = offset;
transfer.count = size;
- transfer.buffer = (void*)buf;
+ memset(transfer.buffer, 0, sizeof(transfer.buffer));
+
+ CHECK(size <= sizeof(transfer.buffer), HAILO_INVALID_ARGUMENT,
+ "Invalid size to write, size given {} is larger than max size {}", size, sizeof(transfer.buffer));
+
+ memcpy(transfer.buffer, buf, transfer.count);
if (0 > ioctl(this->m_fd, HAILO_BAR_TRANSFER, &data)) {
LOGGER__ERROR("HailoRTDriver::write_bar failed with errno: {}", errno);
return HAILO_INVALID_OPERATION;
}
+Expected<std::pair<uintptr_t, uint64_t>> HailoRTDriver::vdma_continuous_buffer_alloc(size_t size)
+{
+ (void) size;
+ return make_unexpected(HAILO_INVALID_OPERATION);
+}
+
+hailo_status HailoRTDriver::vdma_continuous_buffer_free(uintptr_t buffer_handle)
+{
+ (void) buffer_handle;
+ return HAILO_INVALID_OPERATION;
+}
+
hailo_status HailoRTDriver::mark_as_used()
{
tCompatibleHailoIoctlData data = {};
PcieInputStream::PcieInputStream(
PcieDevice &device,
- uint8_t channel_index,
+ std::shared_ptr<VdmaChannel> channel,
const LayerInfo &edge_layer,
EventPtr network_group_activated_event,
uint16_t batch_size,
- LatencyMeterPtr latency_meter,
const std::chrono::milliseconds &transfer_timeout,
hailo_status &status) :
- VdmaInputStream(device, channel_index, edge_layer, network_group_activated_event,
- batch_size, latency_meter, transfer_timeout, HAILO_STREAM_INTERFACE_PCIE, status)
+ VdmaInputStream(device, std::move(channel), edge_layer, network_group_activated_event,
+ batch_size, transfer_timeout, HAILO_STREAM_INTERFACE_PCIE, status)
{}
Expected<std::unique_ptr<PcieInputStream>> PcieInputStream::create(Device &device,
- uint8_t channel_index, const LayerInfo &edge_layer, uint16_t batch_size,
- EventPtr network_group_activated_event, LatencyMeterPtr latency_meter)
+ std::shared_ptr<VdmaChannel> channel, const LayerInfo &edge_layer,
+ uint16_t batch_size, EventPtr network_group_activated_event)
{
hailo_status status = HAILO_UNINITIALIZED;
PcieDevice *pcie_device = reinterpret_cast<PcieDevice*>(&device);
std::unique_ptr<PcieInputStream> local_stream(new (std::nothrow) PcieInputStream(*pcie_device,
- channel_index, edge_layer, std::move(network_group_activated_event), batch_size,
- latency_meter, DEFAULT_TRANSFER_TIMEOUT, status));
+ std::move(channel), edge_layer, std::move(network_group_activated_event), batch_size,
+ DEFAULT_TRANSFER_TIMEOUT, status));
CHECK((nullptr != local_stream), make_unexpected(HAILO_OUT_OF_HOST_MEMORY));
CHECK_SUCCESS_AS_EXPECTED(status);
}
Expected<std::unique_ptr<PcieOutputStream>> PcieOutputStream::create(Device &device,
- uint8_t channel_index, const LayerInfo &edge_layer, uint16_t batch_size,
- EventPtr network_group_activated_event, LatencyMeterPtr latency_meter)
+ std::shared_ptr<VdmaChannel> channel, const LayerInfo &edge_layer, uint16_t batch_size,
+ EventPtr network_group_activated_event)
{
hailo_status status = HAILO_UNINITIALIZED;
PcieDevice *pcie_device = reinterpret_cast<PcieDevice*>(&device);
std::unique_ptr<PcieOutputStream> local_stream(new (std::nothrow) PcieOutputStream(*pcie_device,
- channel_index, edge_layer, std::move(network_group_activated_event),
- batch_size, latency_meter, DEFAULT_TRANSFER_TIMEOUT, status));
+ std::move(channel), edge_layer, std::move(network_group_activated_event),
+ batch_size, DEFAULT_TRANSFER_TIMEOUT, status));
CHECK((nullptr != local_stream), make_unexpected(HAILO_OUT_OF_HOST_MEMORY));
CHECK_SUCCESS_AS_EXPECTED(status);
PcieOutputStream::PcieOutputStream(
PcieDevice &device,
- uint8_t channel_index,
+ std::shared_ptr<VdmaChannel> channel,
const LayerInfo &edge_layer,
EventPtr network_group_activated_event,
uint16_t batch_size,
- LatencyMeterPtr latency_meter,
const std::chrono::milliseconds &transfer_timeout,
hailo_status &status) :
- VdmaOutputStream(device, channel_index, edge_layer,
- network_group_activated_event, batch_size, latency_meter, transfer_timeout, status)
+ VdmaOutputStream(device, std::move(channel), edge_layer,
+ network_group_activated_event, batch_size, transfer_timeout, status)
{}
} /* namespace hailort */
PcieInputStream(PcieInputStream &&other) = default;
virtual ~PcieInputStream() = default;
- static Expected<std::unique_ptr<PcieInputStream>> create(Device &device, uint8_t channel_index,
- const LayerInfo &edge_layer, uint16_t batch_size, EventPtr network_group_activated_event,
- LatencyMeterPtr latency_meter = nullptr);
+ static Expected<std::unique_ptr<PcieInputStream>> create(Device &device,
+ std::shared_ptr<VdmaChannel> channel, const LayerInfo &edge_layer, uint16_t batch_size,
+ EventPtr network_group_activated_event);
virtual hailo_stream_interface_t get_interface() const override { return HAILO_STREAM_INTERFACE_PCIE; }
private:
PcieInputStream(
PcieDevice &device,
- uint8_t channel_index,
+ std::shared_ptr<VdmaChannel> channel,
const LayerInfo &edge_layer,
EventPtr network_group_activated_event,
uint16_t batch_size,
- LatencyMeterPtr latency_meter,
const std::chrono::milliseconds &transfer_timeout,
hailo_status &status);
PcieOutputStream(PcieOutputStream &&other) = default;
virtual ~PcieOutputStream() = default;
- static Expected<std::unique_ptr<PcieOutputStream>> create(Device &device, uint8_t channel_index,
- const LayerInfo &edge_layer, uint16_t batch_size, EventPtr network_group_activated_event,
- LatencyMeterPtr latency_meter);
+ static Expected<std::unique_ptr<PcieOutputStream>> create(Device &device,
+ std::shared_ptr<VdmaChannel> channel, const LayerInfo &edge_layer, uint16_t batch_size,
+ EventPtr network_group_activated_event);
virtual hailo_stream_interface_t get_interface() const override { return HAILO_STREAM_INTERFACE_PCIE; }
private:
explicit PcieOutputStream(
PcieDevice &device,
- uint8_t channel_index,
+ std::shared_ptr<VdmaChannel> channel,
const LayerInfo &edge_layer,
EventPtr network_group_activated_event,
uint16_t batch_size,
- LatencyMeterPtr latency_meter,
const std::chrono::milliseconds &transfer_timeout,
hailo_status &status);
};
#include "pipeline.hpp"
#include "common/utils.hpp"
#include "common/runtime_statistics_internal.hpp"
+#include "microprofile.h"
namespace hailort
{
void BaseQueueElement::start_thread()
{
m_thread = std::thread([this] () {
+ // Microprofile the thread
+ MicroProfileOnThreadCreate(name().c_str());
+ MicroProfileSetEnableAllGroups(true);
+ MicroProfileSetForceMetaCounters(true);
+
while (m_is_thread_running.load()) {
auto status = m_activation_event.wait(INIFINITE_TIMEOUT());
}
}
}
+ // TODO: Should we use MicroProfileShutdown?
+ MicroProfileOnThreadExit();
});
}
if (HAILO_SUCCESS != status) {
// We want to deactivate source even if enqueue failed
auto deactivation_status = next_pad().deactivate();
- if (HAILO_SUCCESS != deactivation_status) {
- LOGGER__ERROR("Deactivate of source in {} has failed with status {}", name(), status);
- // TODO (HRT-4156): return error status?
- }
+ CHECK_SUCCESS(deactivation_status);
if ((HAILO_STREAM_INTERNAL_ABORT == status) || (HAILO_SHUTDOWN_EVENT_SIGNALED == status)) {
LOGGER__INFO("enqueue() in element {} was aborted, got status = {}", name(), status);
- } else {
- LOGGER__ERROR("enqueue() in element {} failed, got status = {}", name(), status);
+ }
+ else {
+ LOGGER__ERROR("enqueue() in element {} failed, got status = {}", name(), status);
+ return status;
}
}
hailo_status PullQueueElement::deactivate()
{
hailo_status status = next_pad().deactivate();
- if (HAILO_SUCCESS != status) {
- LOGGER__ERROR("deactivate of source in {} has failed with status {}", name(), status);
- }
-
- status = m_shutdown_event->signal();
- if (HAILO_SUCCESS != status) {
- LOGGER__CRITICAL("Signaling shutdown event has failed with status = {}", status);
- }
+ auto shutdown_event_status = m_shutdown_event->signal();
+ CHECK_SUCCESS(status);
+ CHECK_SUCCESS(shutdown_event_status);
return HAILO_SUCCESS;
}
// deactivate should be called before mutex acquire and notify_all because it is possible that all queues are waiting on
// the run_pull of the source (HwRead) and the mutex is already acquired so this would prevent a timeout error
hailo_status status = next_pad().deactivate();
- if (HAILO_SUCCESS != status) {
- LOGGER__ERROR("deactivate of source in {} has failed with status {}", name(), status);
- }
{
// There is a case where the other thread is halted (via context switch) before the wait_for() function,
}
m_cv.notify_all();
+ CHECK_SUCCESS(status);
+
return HAILO_SUCCESS;
}
#include "hailo/transform.hpp"
#include "common/utils.hpp"
#include "hef_internal.hpp"
+#include "microprofile.h"
#include <sstream>
hailo_status InputStream::write(const MemoryView &buffer)
{
+ MICROPROFILE_SCOPEI("Stream", "Write", 0);
CHECK((buffer.size() % m_stream_info.hw_frame_size) == 0, HAILO_INVALID_ARGUMENT,
"write size {} must be a multiple of hw size {}", buffer.size(), m_stream_info.hw_frame_size);
CHECK(((buffer.size() % HailoRTCommon::HW_DATA_ALIGNMENT) == 0), HAILO_INVALID_ARGUMENT,
"Input must be aligned to {} (got {})", HailoRTCommon::HW_DATA_ALIGNMENT, buffer.size());
- return sync_write_all_raw_buffer_no_transform_impl(const_cast<uint8_t*>(buffer.data()), 0, buffer.size());
+ auto status = sync_write_all_raw_buffer_no_transform_impl(const_cast<uint8_t*>(buffer.data()), 0, buffer.size());
+ MicroProfileFlip(nullptr);
+ return status;
}
std::string InputStream::to_string() const
CHECK(transfer_size == bbox_size, HAILO_INTERNAL_FAILURE,
"Data read from the device was size {}, should be bbox size {}", transfer_size, bbox_size);
+ if (HailoRTCommon::NMS_DUMMY_DELIMITER == *(uint64_t*)((uint8_t*)buffer + offset)) {
+ continue;
+ }
+
if (HailoRTCommon::NMS_DELIMITER == *(uint64_t*)((uint8_t*)buffer + offset)) {
break;
}
hailo_status OutputStream::read(MemoryView buffer)
{
+ MICROPROFILE_SCOPEI("Stream", "Read", 0);
CHECK((buffer.size() % m_stream_info.hw_frame_size) == 0, HAILO_INVALID_ARGUMENT,
"When read size {} must be a multiple of hw size {}", buffer.size(), m_stream_info.hw_frame_size);
return m_network_group_activated_event;
}
+bool InputStreamBase::is_scheduled()
+{
+ return false;
+}
+
EventPtr &OutputStreamBase::get_network_group_activated_event()
{
return m_network_group_activated_event;
}
+bool OutputStreamBase::is_scheduled()
+{
+ return false;
+}
+
} /* namespace hailort */
}
virtual EventPtr &get_network_group_activated_event() override;
+ virtual bool is_scheduled() override;
private:
EventPtr m_network_group_activated_event;
}
virtual EventPtr &get_network_group_activated_event() override;
+ virtual bool is_scheduled() override;
LayerInfo m_layer_info;
#include "common/logger_macros.hpp"
#include "common/utils.hpp"
#include "transform_internal.hpp"
+#include "microprofile.h"
#include <type_traits>
#include <sstream>
return HAILO_SUCCESS;
}
- if ((HAILO_FORMAT_ORDER_FCR == src_format.order) &&
+ if (((HAILO_FORMAT_ORDER_FCR == src_format.order) || (HAILO_FORMAT_ORDER_NHWC == src_format.order)) &&
(HAILO_FORMAT_ORDER_FCR == dst_format.order)) {
assert(0 == (dst_image_shape.features % 8));
switch (dst_format.type) {
return HAILO_SUCCESS;
}
- if ((HAILO_FORMAT_ORDER_F8CR == src_format.order) &&
+ if (((HAILO_FORMAT_ORDER_F8CR == src_format.order) || (HAILO_FORMAT_ORDER_NHWC == src_format.order)) &&
(HAILO_FORMAT_ORDER_F8CR == dst_format.order)) {
switch (dst_format.type) {
case HAILO_FORMAT_TYPE_UINT8:
}
}
else if ((HAILO_FORMAT_ORDER_FCR == src_format.order) &&
- (HAILO_FORMAT_ORDER_FCR == dst_format.order)) {
+ ((HAILO_FORMAT_ORDER_FCR == dst_format.order) || (HAILO_FORMAT_ORDER_NHWC == dst_format.order))) {
switch (src_format.type) {
case HAILO_FORMAT_TYPE_UINT8:
transform__d2h_NHWC_to_NHWC<uint8_t>((uint8_t*)src_ptr, &src_image_shape, (uint8_t*)dst_ptr, &dst_image_shape);
}
}
else if ((HAILO_FORMAT_ORDER_F8CR == src_format.order) &&
- (HAILO_FORMAT_ORDER_F8CR == dst_format.order)) {
+ ((HAILO_FORMAT_ORDER_F8CR == dst_format.order) || (HAILO_FORMAT_ORDER_NHWC == dst_format.order))) {
switch (src_format.type) {
case HAILO_FORMAT_TYPE_UINT8:
transform__d2h_F8CR<uint8_t>((uint8_t*)src_ptr, &src_image_shape, (uint8_t*)dst_ptr, &dst_image_shape);
hailo_status transform_demux_raw_frame(const void *src, uint32_t offset,
hailo_mux_info_t *mux_info, uint32_t mux_row_count)
{
+ MICROPROFILE_SCOPEI("Transformations", "Demux", 0);
// This is a recursive function with a maximum depth of HailoRTCommon::MUX_INFO_COUNT.
hailo_status status = HAILO_UNINITIALIZED;
struct hailo_mux_info_t *predecessor = NULL;
hailo_status InputTransformContext::transform(const MemoryView src, MemoryView dst)
{
+ MICROPROFILE_SCOPEI("Transformations", "H2D transform", 0);
/* Check sizes */
CHECK(src.size() == m_src_frame_size, HAILO_INVALID_ARGUMENT,
"src size must be {}. passed size - {}", m_src_frame_size, src.size());
hailo_status FrameOutputTransformContext::transform(const MemoryView src, MemoryView dst)
{
+ MICROPROFILE_SCOPEI("Transformations", "D2H transform", 0);
/* Check sizes */
CHECK(src.size() == m_src_frame_size, HAILO_INVALID_ARGUMENT,
"src size must be {}. passed size - {}", m_src_frame_size, src.size());
hailo_status NMSOutputTransformContext::transform(const MemoryView src, MemoryView dst)
{
+ MICROPROFILE_SCOPEI("Transformations", "D2H NMS transform", 0);
/* Check sizes */
CHECK(src.size() == m_src_frame_size, HAILO_INVALID_ARGUMENT,
"src size must be {}. passed size - {}", m_src_frame_size, src.size());
hailo_status fuse_buffers(const std::vector<MemoryView> &buffers,
const std::vector<hailo_nms_info_t> &infos_of_buffers, MemoryView dst)
{
+ MICROPROFILE_SCOPEI("Transformations", "Fuse NMS", 0);
CHECK_ARG_NOT_NULL(dst.data());
CHECK(buffers.size() == infos_of_buffers.size(), HAILO_INVALID_ARGUMENT,
"Vectors of buffers and NMS infos does not match!");
{
CHECK_AS_EXPECTED(0 != params.device_count, HAILO_INVALID_ARGUMENT,
"VDevice creation failed. invalid device_count ({}).", params.device_count);
+
+ CHECK_AS_EXPECTED((HAILO_SCHEDULING_ALGORITHM_NONE == params.scheduling_algorithm) || (1 == params.device_count), HAILO_INVALID_ARGUMENT,
+ "Network group scheduler can be active only when using one device in the vDevice!");
auto vdevice = VDeviceBase::create(params);
CHECK_EXPECTED(vdevice);
Expected<std::unique_ptr<VDeviceBase>> VDeviceBase::create(const hailo_vdevice_params_t ¶ms)
{
+ NetworkGroupSchedulerPtr scheduler_ptr;
+ if (HAILO_SCHEDULING_ALGORITHM_NONE != params.scheduling_algorithm) {
+ auto network_group_scheduler = NetworkGroupScheduler::create_shared(params.scheduling_algorithm);
+ CHECK_EXPECTED(network_group_scheduler);
+ scheduler_ptr = network_group_scheduler.release();
+ }
+
auto scan_res = PcieDevice::scan();
CHECK_EXPECTED(scan_res);
CHECK_AS_EXPECTED(params.device_count == devices.size(), HAILO_OUT_OF_PHYSICAL_DEVICES,
"Failed to create vdevice. there are not enough free devices. requested: {}, found: {}",
params.device_count, devices.size());
- auto vdevice = std::unique_ptr<VDeviceBase>(new (std::nothrow) VDeviceBase(std::move(devices)));
+
+ std::string vdevice_infos = "VDevice Infos:";
+ for (const auto &device : devices) {
+ auto info_str = PcieDevice::pcie_device_info_to_string(device->get_device_info());
+ CHECK_EXPECTED(info_str);
+
+ vdevice_infos += " " + info_str.value();
+ }
+ LOGGER__INFO("{}", vdevice_infos);
+
+ auto vdevice = std::unique_ptr<VDeviceBase>(new (std::nothrow) VDeviceBase(std::move(devices), scheduler_ptr));
CHECK_AS_EXPECTED(nullptr != vdevice, HAILO_OUT_OF_HOST_MEMORY);
return vdevice;
}
+// TODO - make this function thread-safe.
Expected<ConfiguredNetworkGroupVector> VDeviceBase::configure(Hef &hef,
const NetworkGroupsParamsMap &configure_params)
{
auto start_time = std::chrono::steady_clock::now();
if (!m_context_switch_manager) {
-
auto local_context_switch_manager = VdmaConfigManager::create(*this);
CHECK_EXPECTED(local_context_switch_manager);
m_context_switch_manager = make_unique_nothrow<VdmaConfigManager>(local_context_switch_manager.release());
CHECK_AS_EXPECTED(nullptr != m_context_switch_manager, HAILO_OUT_OF_HOST_MEMORY);
}
- auto network_groups = m_context_switch_manager->add_hef(hef, configure_params);
+ bool is_scheduler_used = (m_network_group_scheduler != nullptr);
+ auto network_groups = m_context_switch_manager->add_hef(hef, configure_params, is_scheduler_used);
CHECK_EXPECTED(network_groups);
auto elapsed_time_ms = std::chrono::duration<double, std::milli>(std::chrono::steady_clock::now() - start_time).count();
#include "hailo/vdevice.hpp"
#include "pcie_device.hpp"
#include "context_switch/multi_context/vdma_config_manager.hpp"
+#include "network_group_scheduler.hpp"
namespace hailort
return devices_infos;
}
+ const NetworkGroupSchedulerPtr &network_group_scheduler()
+ {
+ return m_network_group_scheduler;
+ }
+
private:
- VDeviceBase(std::vector<std::unique_ptr<PcieDevice>> &&devices) : m_devices(std::move(devices))
+ VDeviceBase(std::vector<std::unique_ptr<PcieDevice>> &&devices, NetworkGroupSchedulerPtr network_group_scheduler) :
+ m_devices(std::move(devices)), m_network_group_scheduler(network_group_scheduler)
{}
std::vector<std::unique_ptr<PcieDevice>> m_devices;
std::unique_ptr<VdmaConfigManager> m_context_switch_manager;
-
+ NetworkGroupSchedulerPtr m_network_group_scheduler;
};
} /* namespace hailort */
}
}
-hailo_status VDeviceInputStream::activate_stream()
+hailo_status VDeviceInputStream::activate_stream(uint16_t dynamic_batch_size)
{
for (auto &stream : m_streams) {
- auto status = stream->activate_stream();
+ auto status = stream->activate_stream(dynamic_batch_size);
if (HAILO_SUCCESS != status) {
LOGGER__ERROR("Failed to activate input stream. (device: {})", stream->get_dev_id());
deactivate_stream();
Expected<size_t> VDeviceInputStream::sync_write_raw_buffer(const MemoryView &buffer)
{
- auto written_bytes = m_streams[m_next_transfer_stream_index]->sync_write_raw_buffer(buffer);
- if (HAILO_SUCCESS != written_bytes.status()) {
- LOGGER__INFO("Write to stream has failed! status = {}", written_bytes.status());
- return make_unexpected(written_bytes.status());
+ size_t written_bytes = 0;
+ auto network_group_scheduler = m_network_group_scheduler.lock();
+ if (network_group_scheduler) {
+ auto status = network_group_scheduler->wait_for_write(m_network_group_handle, name());
+ if (HAILO_STREAM_INTERNAL_ABORT == status) {
+ LOGGER__INFO("Write to stream was aborted.");
+ return make_unexpected(status);
+ }
+ CHECK_SUCCESS_AS_EXPECTED(status);
+
+ status = m_streams[m_next_transfer_stream_index]->write_buffer_only(buffer);
+ if (HAILO_SUCCESS != status) {
+ LOGGER__INFO("Write to stream has failed! status = {}", status);
+ return make_unexpected(status);
+ }
+
+ status = network_group_scheduler->signal_write_finish(m_network_group_handle, name());
+ if (HAILO_STREAM_INTERNAL_ABORT == status) {
+ return make_unexpected(status);
+ }
+ CHECK_SUCCESS_AS_EXPECTED(status);
+
+ written_bytes = buffer.size();
+ } else {
+ auto expected_written_bytes = m_streams[m_next_transfer_stream_index]->sync_write_raw_buffer(buffer);
+ if (HAILO_SUCCESS != expected_written_bytes.status()) {
+ LOGGER__INFO("Write to stream has failed! status = {}", expected_written_bytes.status());
+ return make_unexpected(expected_written_bytes.status());
+ }
+ written_bytes = expected_written_bytes.value();
}
// Update m_next_transfer_stream_index only if 'batch' frames has been transferred
- if (0 == (++m_acc_frames % m_streams[0]->get_batch_size())) {
+ if (0 == (++m_acc_frames % m_streams[0]->get_dynamic_batch_size())) {
m_next_transfer_stream_index = static_cast<uint32_t>((m_next_transfer_stream_index + 1) % m_streams.size());
m_acc_frames = 0;
}
- return written_bytes.release();
+ return written_bytes;
}
hailo_status VDeviceInputStream::sync_write_all_raw_buffer_no_transform_impl(void *buffer, size_t offset, size_t size)
return sync_write_raw_buffer(MemoryView(static_cast<uint8_t*>(buffer) + offset, size)).status();
}
+Expected<PendingBufferState> VDeviceInputStream::send_pending_buffer()
+{
+ assert(1 == m_streams.size());
+ VdmaInputStream &vdma_input = dynamic_cast<VdmaInputStream&>(*m_streams[m_next_transfer_stream_index].get());
+ return vdma_input.send_pending_buffer();
+}
+
+// TODO - HRT-6830 - make create_input/output_stream_from_net_group as virutal function
Expected<std::unique_ptr<VDeviceInputStream>> VDeviceInputStream::create_input_stream_from_net_group(
std::vector<std::shared_ptr<ResourcesManager>> &resources_managers,
- const LayerInfo &edge_layer, const std::string &stream_name,
- EventPtr &&network_group_activated_event, LatencyMeterPtr latency_meter)
+ const LayerInfo &edge_layer, const std::string &stream_name, const network_group_handle_t &network_group_handle,
+ EventPtr &&network_group_activated_event, NetworkGroupSchedulerWeakPtr network_group_scheduler)
{
hailo_status status = HAILO_UNINITIALIZED;
- const auto stream_index = edge_layer.index;
- // Channel index is the same through all resources_managers
- const auto channel_index = resources_managers[0]->get_boundary_channel_index(stream_index, HAILO_H2D_STREAM, stream_name);
- CHECK_EXPECTED(channel_index, "Failed to get channel index for input stream {}", stream_index);
-
std::vector<PcieDevice*> devices;
std::vector<std::unique_ptr<PcieInputStream>> streams;
- auto partial_network_name = edge_layer.partial_network_name;
for (auto &resources_manager : resources_managers) {
CHECK_AS_EXPECTED(Device::Type::PCIE == resources_manager->get_device().get_type(), HAILO_INTERNAL_FAILURE,
"vDevice stream is supported only with PCIe devices");
PcieDevice &pcie_device = reinterpret_cast<PcieDevice&>(resources_manager->get_device());
- auto batch_size = resources_manager->get_network_batch_size_from_partial_name(partial_network_name);
- auto local_stream = PcieInputStream::create(pcie_device, channel_index.value(),
- edge_layer, batch_size.value(), network_group_activated_event, latency_meter);
+ auto vdma_channel_ptr = resources_manager->get_boundary_vdma_channel_by_stream_name(stream_name);
+ CHECK_EXPECTED(vdma_channel_ptr);
+
+ auto batch_size = resources_manager->get_network_batch_size(edge_layer.network_name);
+ auto local_stream = PcieInputStream::create(pcie_device,
+ vdma_channel_ptr.release(), edge_layer, batch_size.value(), network_group_activated_event);
CHECK_EXPECTED(local_stream);
devices.push_back(&pcie_device);
}
std::unique_ptr<VDeviceInputStream> local_vdevice_stream(new (std::nothrow) VDeviceInputStream(devices,
- std::move(streams), std::move(network_group_activated_event), edge_layer, status));
+ std::move(streams), network_group_handle, std::move(network_group_activated_event), edge_layer, network_group_scheduler, status));
CHECK_AS_EXPECTED((nullptr != local_vdevice_stream), HAILO_OUT_OF_HOST_MEMORY);
CHECK_SUCCESS_AS_EXPECTED(status);
}
Expected<std::unique_ptr<VDeviceInputStream>> VDeviceInputStream::create(std::vector<std::shared_ptr<ResourcesManager>> &resources_managers,
- const LayerInfo &edge_layer, const std::string &stream_name, EventPtr network_group_activated_event, LatencyMeterPtr latency_meter)
+ const LayerInfo &edge_layer, const std::string &stream_name, const network_group_handle_t &network_group_handle, EventPtr network_group_activated_event,
+ NetworkGroupSchedulerWeakPtr network_group_scheduler)
{
assert(0 < resources_managers.size());
auto input_stream = create_input_stream_from_net_group(resources_managers, edge_layer,
- stream_name, std::move(network_group_activated_event), latency_meter);
+ stream_name, network_group_handle, std::move(network_group_activated_event), network_group_scheduler);
CHECK_EXPECTED(input_stream);
return input_stream.release();
status = abort_status;
}
}
+
+ auto network_group_scheduler = m_network_group_scheduler.lock();
+ if (network_group_scheduler) {
+ auto disable_status = network_group_scheduler->disable_stream(m_network_group_handle, name());
+ if (HAILO_SUCCESS != disable_status) {
+ LOGGER__ERROR("Failed to disable stream in the network group scheduler. (status: {})", disable_status);
+ status = disable_status;
+ }
+ }
+
return status;
}
auto status = HAILO_SUCCESS; // Best effort
for (auto &stream : m_streams) {
auto clear_abort_status = stream->clear_abort();
- if (HAILO_SUCCESS != status) {
- LOGGER__ERROR("Failed to clear abort input stream. (status: {} device: {})", status, stream->get_dev_id());
+ if ((HAILO_SUCCESS != clear_abort_status) && (HAILO_STREAM_NOT_ACTIVATED != clear_abort_status)) {
+ LOGGER__ERROR("Failed to clear abort input stream. (status: {} device: {})", clear_abort_status, stream->get_dev_id());
status = clear_abort_status;
}
}
+
+ auto network_group_scheduler = m_network_group_scheduler.lock();
+ if (network_group_scheduler) {
+ auto enable_status = network_group_scheduler->enable_stream(m_network_group_handle, name());
+ if (HAILO_SUCCESS != enable_status) {
+ LOGGER__ERROR("Failed to enable stream in the network group scheduler. (status: {})", enable_status);
+ status = enable_status;
+ }
+ }
+
return status;
}
+bool VDeviceInputStream::is_scheduled()
+{
+ auto network_group_scheduler = m_network_group_scheduler.lock();
+ if (!network_group_scheduler) {
+ return false;
+ }
+ return (HAILO_SCHEDULING_ALGORITHM_NONE != network_group_scheduler->algorithm());
+}
+
/** Output stream **/
hailo_status VDeviceOutputStream::deactivate_stream()
{
}
}
-hailo_status VDeviceOutputStream::activate_stream()
+hailo_status VDeviceOutputStream::activate_stream(uint16_t dynamic_batch_size)
{
for (auto &stream : m_streams) {
- auto status = stream->activate_stream();
+ auto status = stream->activate_stream(dynamic_batch_size);
if (HAILO_SUCCESS != status) {
LOGGER__ERROR("Failed to activate output stream. (device: {})", stream->get_dev_id());
deactivate_stream();
hailo_status VDeviceOutputStream::read(MemoryView buffer)
{
+ auto network_group_scheduler = m_network_group_scheduler.lock();
+ if (network_group_scheduler) {
+ auto status = network_group_scheduler->wait_for_read(m_network_group_handle, name());
+ if (HAILO_STREAM_INTERNAL_ABORT == status) {
+ LOGGER__INFO("Read from stream was aborted.");
+ return status;
+ }
+ CHECK_SUCCESS(status);
+ }
+
auto status = m_streams[m_next_transfer_stream_index]->read(buffer);
if (HAILO_SUCCESS != status) {
LOGGER__INFO("Read from stream has failed! status = {}", status);
}
// Update m_next_transfer_stream_index only if 'batch' frames has been transferred
- if (0 == (++m_acc_frames % m_streams[0]->get_batch_size())) {
+ if (0 == (++m_acc_frames % m_streams[0]->get_dynamic_batch_size())) {
m_next_transfer_stream_index = static_cast<uint32_t>((m_next_transfer_stream_index + 1) % m_streams.size());
m_acc_frames = 0;
}
+
+ if (network_group_scheduler) {
+ status = network_group_scheduler->signal_read_finish(m_network_group_handle, name());
+ if (HAILO_STREAM_INTERNAL_ABORT == status) {
+ return status;
+ }
+ CHECK_SUCCESS(status);
+ }
+
return HAILO_SUCCESS;
}
+// TODO - HRT-6830 - make create_input/output_stream_from_net_group as virutal function
Expected<std::unique_ptr<VDeviceOutputStream>> VDeviceOutputStream::create_output_stream_from_net_group(
std::vector<std::shared_ptr<ResourcesManager>> &resources_managers,
- const LayerInfo &edge_layer, const std::string &stream_name,
- EventPtr &&network_group_activated_event, LatencyMeterPtr latency_meter)
+ const LayerInfo &edge_layer, const std::string &stream_name, const network_group_handle_t &network_group_handle,
+ EventPtr &&network_group_activated_event, NetworkGroupSchedulerWeakPtr network_group_scheduler)
{
hailo_status status = HAILO_UNINITIALIZED;
- const auto stream_index = edge_layer.index;
-
- // Channel index is the same through all resources_managers
- const auto channel_index = resources_managers[0]->get_boundary_channel_index(stream_index, HAILO_D2H_STREAM, stream_name);
- CHECK_EXPECTED(channel_index, "Failed to get channel index for output stream {}", stream_index);
-
std::vector<PcieDevice*> devices;
std::vector<std::unique_ptr<PcieOutputStream>> streams;
- auto partial_network_name = edge_layer.partial_network_name;
for (auto &resources_manager : resources_managers) {
CHECK_AS_EXPECTED(Device::Type::PCIE == resources_manager->get_device().get_type(), HAILO_INTERNAL_FAILURE,
"vDevice stream is supported only with PCIe devices");
PcieDevice &pcie_device = reinterpret_cast<PcieDevice&>(resources_manager->get_device());
- auto batch_size = resources_manager->get_network_batch_size_from_partial_name(partial_network_name);
- auto local_stream = PcieOutputStream::create(pcie_device, channel_index.value(),
- edge_layer, batch_size.value(), network_group_activated_event, latency_meter);
+ auto vdma_channel_ptr = resources_manager->get_boundary_vdma_channel_by_stream_name(stream_name);
+ CHECK_EXPECTED(vdma_channel_ptr);
+
+ auto batch_size = resources_manager->get_network_batch_size(edge_layer.network_name);
+ auto local_stream = PcieOutputStream::create(pcie_device,
+ vdma_channel_ptr.release(), edge_layer, batch_size.value(), network_group_activated_event);
CHECK_EXPECTED(local_stream);
devices.push_back(&pcie_device);
streams.emplace_back(local_stream.release());
}
- std::unique_ptr<VDeviceOutputStream> local_vdevice_stream(new (std::nothrow) VDeviceOutputStream(devices, std::move(streams),
- edge_layer, std::move(network_group_activated_event), status));
+ std::unique_ptr<VDeviceOutputStream> local_vdevice_stream(new (std::nothrow) VDeviceOutputStream(devices, std::move(streams), network_group_handle,
+ edge_layer, std::move(network_group_activated_event), network_group_scheduler, status));
CHECK_AS_EXPECTED((nullptr != local_vdevice_stream), HAILO_OUT_OF_HOST_MEMORY);
CHECK_SUCCESS_AS_EXPECTED(status);
}
Expected<std::unique_ptr<VDeviceOutputStream>> VDeviceOutputStream::create(std::vector<std::shared_ptr<ResourcesManager>> &resources_managers,
- const LayerInfo &edge_layer, const std::string &stream_name, EventPtr network_group_activated_event, LatencyMeterPtr latency_meter)
+ const LayerInfo &edge_layer, const std::string &stream_name, const network_group_handle_t &network_group_handle, EventPtr network_group_activated_event,
+ NetworkGroupSchedulerWeakPtr network_group_scheduler)
{
assert(0 < resources_managers.size());
auto output_stream = create_output_stream_from_net_group(resources_managers, edge_layer,
- stream_name, std::move(network_group_activated_event), latency_meter);
+ stream_name, network_group_handle, std::move(network_group_activated_event), network_group_scheduler);
CHECK_EXPECTED(output_stream);
return output_stream.release();
status = abort_status;
}
}
+
+ auto network_group_scheduler = m_network_group_scheduler.lock();
+ if (network_group_scheduler) {
+ auto disable_status = network_group_scheduler->disable_stream(m_network_group_handle, name());
+ if (HAILO_SUCCESS != disable_status) {
+ LOGGER__ERROR("Failed to disable stream in the network group scheduler. (status: {})", disable_status);
+ status = disable_status;
+ }
+ }
+
return status;
}
auto status = HAILO_SUCCESS; // Best effort
for (auto &stream : m_streams) {
auto clear_abort_status = stream->clear_abort();
- if (HAILO_SUCCESS != status) {
- LOGGER__ERROR("Failed to clear abort output stream. (status: {} device: {})", status, stream->get_dev_id());
+ if ((HAILO_SUCCESS != clear_abort_status) && (HAILO_STREAM_NOT_ACTIVATED != clear_abort_status)) {
+ LOGGER__ERROR("Failed to clear abort output stream. (status: {} device: {})", clear_abort_status, stream->get_dev_id());
status = clear_abort_status;
}
}
+
+ auto network_group_scheduler = m_network_group_scheduler.lock();
+ if (network_group_scheduler) {
+ auto enable_status = network_group_scheduler->enable_stream(m_network_group_handle, name());
+ if (HAILO_SUCCESS != enable_status) {
+ LOGGER__ERROR("Failed to enable stream in the network group scheduler. (status: {})", enable_status);
+ status = enable_status;
+ }
+ }
+
return status;
}
+bool VDeviceOutputStream::is_scheduled()
+{
+ auto network_group_scheduler = m_network_group_scheduler.lock();
+ if (!network_group_scheduler) {
+ return false;
+ }
+ return (HAILO_SCHEDULING_ALGORITHM_NONE != network_group_scheduler->algorithm());
+}
+
} /* namespace hailort */
#include "stream_internal.hpp"
#include "hailo/hailort.h"
+#include "vdevice_internal.hpp"
#include "pcie_device.hpp"
#include "pcie_stream.hpp"
#include "hailo/expected.hpp"
public:
VDeviceInputStream(VDeviceInputStream &&other) :
InputStreamBase(std::move(other)),
+ m_network_group_handle(std::move(other.m_network_group_handle)),
+ m_network_group_scheduler(std::move(other.m_network_group_scheduler)),
m_devices(std::move(other.m_devices)),
m_streams(std::move(other.m_streams)),
m_is_stream_activated(std::exchange(other.m_is_stream_activated, false)),
virtual ~VDeviceInputStream();
static Expected<std::unique_ptr<VDeviceInputStream>> create(std::vector<std::shared_ptr<ResourcesManager>> &resources_managers,
- const LayerInfo &edge_layer, const std::string &stream_name, EventPtr network_group_activated_event,
- LatencyMeterPtr latency_meter = nullptr);
+ const LayerInfo &edge_layer, const std::string &stream_name, const network_group_handle_t &network_group_handle, EventPtr network_group_activated_event,
+ NetworkGroupSchedulerWeakPtr network_group_scheduler);
- virtual hailo_status activate_stream() override;
+ virtual hailo_status activate_stream(uint16_t dynamic_batch_size) override;
virtual hailo_status deactivate_stream() override;
virtual hailo_stream_interface_t get_interface() const override { return HAILO_STREAM_INTERFACE_PCIE; }
virtual std::chrono::milliseconds get_timeout() const override;
virtual hailo_status abort() override;
virtual hailo_status clear_abort() override;
+ virtual bool is_scheduled() override;
+
+ Expected<PendingBufferState> send_pending_buffer();
protected:
virtual Expected<size_t> sync_write_raw_buffer(const MemoryView &buffer) override;
explicit VDeviceInputStream(
std::vector<PcieDevice*> devices,
std::vector<std::unique_ptr<PcieInputStream>> &&streams,
+ const network_group_handle_t &network_group_handle,
EventPtr &&network_group_activated_event,
const LayerInfo &layer_info,
+ NetworkGroupSchedulerWeakPtr network_group_scheduler,
hailo_status &status) :
InputStreamBase(layer_info, HAILO_STREAM_INTERFACE_PCIE, std::move(network_group_activated_event), status),
+ m_network_group_handle(network_group_handle),
+ m_network_group_scheduler(network_group_scheduler),
m_devices(devices),
m_streams(std::move(streams)),
m_is_stream_activated(false),
static Expected<std::unique_ptr<VDeviceInputStream>> create_input_stream_from_net_group(
std::vector<std::shared_ptr<ResourcesManager>> &resources_managers,
- const LayerInfo &edge_layer, const std::string &stream_name,
- EventPtr &&network_group_activated_event, LatencyMeterPtr latency_meter);
+ const LayerInfo &edge_layer, const std::string &stream_name, const network_group_handle_t &network_group_handle,
+ EventPtr &&network_group_activated_event, NetworkGroupSchedulerWeakPtr network_group_scheduler);
+ network_group_handle_t m_network_group_handle;
+ NetworkGroupSchedulerWeakPtr m_network_group_scheduler;
std::vector<PcieDevice*> m_devices;
std::vector<std::unique_ptr<PcieInputStream>> m_streams;
bool m_is_stream_activated;
public:
VDeviceOutputStream(VDeviceOutputStream &&other) :
OutputStreamBase(std::move(other)),
+ m_network_group_handle(std::move(other.m_network_group_handle)),
+ m_network_group_scheduler(std::move(other.m_network_group_scheduler)),
m_devices(std::move(other.m_devices)),
m_streams(std::move(other.m_streams)),
m_is_stream_activated(std::exchange(other.m_is_stream_activated, false)),
virtual ~VDeviceOutputStream();
static Expected<std::unique_ptr<VDeviceOutputStream>> create(std::vector<std::shared_ptr<ResourcesManager>> &resources_managers,
- const LayerInfo &edge_layer, const std::string &stream_name,
- EventPtr network_group_activated_event, LatencyMeterPtr latency_meter = nullptr);
+ const LayerInfo &edge_layer, const std::string &stream_name, const network_group_handle_t &network_group_handle,
+ EventPtr network_group_activated_event, NetworkGroupSchedulerWeakPtr network_group_scheduler);
- virtual hailo_status activate_stream() override;
+ virtual hailo_status activate_stream(uint16_t dynamic_batch_size) override;
virtual hailo_status deactivate_stream() override;
virtual hailo_stream_interface_t get_interface() const override { return HAILO_STREAM_INTERFACE_PCIE; }
virtual std::chrono::milliseconds get_timeout() const override;
virtual hailo_status abort() override;
virtual hailo_status clear_abort() override;
+ virtual bool is_scheduled() override;
protected:
virtual Expected<size_t> sync_read_raw_buffer(MemoryView &buffer) override;
explicit VDeviceOutputStream(
std::vector<PcieDevice*> devices,
std::vector<std::unique_ptr<PcieOutputStream>> &&streams,
+ const network_group_handle_t &network_group_handle,
const LayerInfo &layer_info,
EventPtr &&network_group_activated_event,
+ NetworkGroupSchedulerWeakPtr network_group_scheduler,
hailo_status &status) :
OutputStreamBase(layer_info, std::move(network_group_activated_event), status),
+ m_network_group_handle(network_group_handle),
+ m_network_group_scheduler(network_group_scheduler),
m_devices(devices),
m_streams(std::move(streams)),
m_is_stream_activated(false),
static Expected<std::unique_ptr<VDeviceOutputStream>> create_output_stream_from_net_group(
std::vector<std::shared_ptr<ResourcesManager>> &resources_managers, const LayerInfo &edge_layer,
- const std::string &stream_name, EventPtr &&network_group_activated_event, LatencyMeterPtr latency_meter);
+ const std::string &stream_name, const network_group_handle_t &network_group_handle, EventPtr &&network_group_activated_event,
+ NetworkGroupSchedulerWeakPtr network_group_scheduler);
+ network_group_handle_t m_network_group_handle;
+ NetworkGroupSchedulerWeakPtr m_network_group_scheduler;
std::vector<PcieDevice*> m_devices;
std::vector<std::unique_ptr<PcieOutputStream>> m_streams;
bool m_is_stream_activated;
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file continuous_buffer.hpp
+ * @brief Continuous physical vdma buffer.
+ **/
+
+#include "continuous_buffer.hpp"
+
+namespace hailort {
+namespace vdma {
+
+// Minimum size of ccb buffers in descriptors, taken from the CCB spec.
+#define MIN_CCB_DESCRIPTORS_COUNT (16)
+
+static uint32_t align(uint32_t size, uint32_t align)
+{
+ assert(is_powerof2(align));
+ const uint32_t mask = align - 1;
+ return (size + mask) & ~mask;
+}
+
+Expected<ContinuousBuffer> ContinuousBuffer::create(size_t size, HailoRTDriver &driver)
+{
+ auto result = driver.vdma_continuous_buffer_alloc(size);
+ CHECK_EXPECTED(result, "Failed allocating continuous buffer, size {}", size);
+
+ uintptr_t handle = 0;
+ uint64_t dma_address = 0;
+ std::tie(handle, dma_address) = result.release();
+
+ auto mmap = MmapBuffer<void>::create_file_map(size, driver.fd(), handle);
+ if (!mmap) {
+ LOGGER__ERROR("Failed mmap continuous buffer");
+ driver.vdma_continuous_buffer_free(handle);
+ return make_unexpected(mmap.status());
+ }
+
+ return ContinuousBuffer(size, driver, handle, dma_address, mmap.release());
+}
+
+uint32_t ContinuousBuffer::get_buffer_size(uint32_t buffer_size)
+{
+ const uint16_t page_size = DEFAULT_DESC_PAGE_SIZE;
+ const auto aligned_buffer_size = align(buffer_size, page_size);
+
+ const uint32_t min_buffer_size = page_size * MIN_CCB_DESCRIPTORS_COUNT;
+ return std::max(aligned_buffer_size, min_buffer_size);
+}
+
+uint32_t ContinuousBuffer::get_buffer_size_desc_power2(uint32_t buffer_size)
+{
+ const uint16_t page_size = DEFAULT_DESC_PAGE_SIZE;
+ const auto descriptors_in_buffer = DESCRIPTORS_IN_BUFFER(buffer_size, page_size);
+ const auto actual_descriptors_count = get_nearest_powerof_2(descriptors_in_buffer, MIN_CCB_DESCRIPTORS_COUNT);
+ return actual_descriptors_count * page_size;
+}
+
+ContinuousBuffer::~ContinuousBuffer()
+{
+ if (0 != m_handle) {
+ auto status = m_mmap.unmap();
+ if (HAILO_SUCCESS != status) {
+ LOGGER__ERROR("Failed unmap mmap buffer {}", status);
+ }
+
+ status = m_driver.vdma_continuous_buffer_free(m_handle);
+ if (HAILO_SUCCESS != status) {
+ LOGGER__ERROR("Failed free continuous buffer, {}", status);
+ }
+
+ m_handle = 0;
+ }
+}
+
+size_t ContinuousBuffer::size() const
+{
+ return m_size;
+}
+
+uint64_t ContinuousBuffer::dma_address() const
+{
+ return m_dma_address;
+}
+
+uint16_t ContinuousBuffer::desc_page_size() const
+{
+ // Currently we support only the default desc page size, TODO: HRT-5381 support more desc page size?
+ return DEFAULT_DESC_PAGE_SIZE;
+}
+
+uint32_t ContinuousBuffer::descs_count() const
+{
+ return descriptors_in_buffer(m_size);
+}
+
+hailo_status ContinuousBuffer::read(void *buf_dst, size_t count, size_t offset)
+{
+ CHECK((count + offset) <= m_size, HAILO_INSUFFICIENT_BUFFER,
+ "Requested size {} from offset {} is more than the buffer size {}", count, offset, m_size);
+ // We use dma coherent mmap, so no need to sync the buffer after the memcpy.
+ const auto src_address = reinterpret_cast<uint8_t*>(m_mmap.get()) + offset;
+ memcpy(buf_dst, src_address, count);
+ return HAILO_SUCCESS;
+}
+
+hailo_status ContinuousBuffer::write(const void *buf_src, size_t count, size_t offset)
+{
+ CHECK((count + offset) <= m_size, HAILO_INSUFFICIENT_BUFFER,
+ "Requested size {} from offset {} is more than the buffer size {}", count, offset, m_size);
+ // We use dma coherent mmap, so no need to sync the buffer after the memcpy.
+ const auto dst_address = reinterpret_cast<uint8_t*>(m_mmap.get()) + offset;
+ memcpy(dst_address, buf_src, count);
+ return HAILO_SUCCESS;
+}
+
+Expected<uint32_t> ContinuousBuffer::program_descriptors(size_t transfer_size, VdmaInterruptsDomain first_desc_interrupts_domain,
+ VdmaInterruptsDomain last_desc_interrupts_domain, size_t desc_offset, bool is_circular)
+{
+ (void)first_desc_interrupts_domain;
+ (void)last_desc_interrupts_domain;
+ (void)desc_offset;
+ (void)is_circular;
+
+ // The descriptors in continuous mode are programmed by the hw, nothing to do here.
+ return descriptors_in_buffer(transfer_size);
+}
+
+hailo_status ContinuousBuffer::reprogram_device_interrupts_for_end_of_batch(size_t transfer_size, uint16_t batch_size,
+ VdmaInterruptsDomain new_interrupts_domain)
+{
+ (void)transfer_size;
+ (void)batch_size;
+ (void)new_interrupts_domain;
+
+ // The descriptors in continuous mode are programmed by the hw, nothing to do here.
+ return HAILO_SUCCESS;
+}
+
+ContinuousBuffer::ContinuousBuffer(size_t size, HailoRTDriver &driver, uintptr_t handle, uint64_t dma_address,
+ MmapBuffer<void> &&mmap) :
+ m_size(size),
+ m_driver(driver),
+ m_handle(handle),
+ m_dma_address(dma_address),
+ m_mmap(std::move(mmap))
+{}
+
+}; /* namespace vdma */
+}; /* namespace hailort */
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file continuous_buffer.hpp
+ * @brief Continuous physical vdma buffer.
+ **/
+
+#ifndef _HAILO_VDMA_CONTINUOUS_BUFFER_HPP_
+#define _HAILO_VDMA_CONTINUOUS_BUFFER_HPP_
+
+#include "os/hailort_driver.hpp"
+#include "os/mmap_buffer.hpp"
+#include "vdma/vdma_buffer.hpp"
+
+namespace hailort {
+namespace vdma {
+
+class ContinuousBuffer final : public VdmaBuffer {
+public:
+ static Expected<ContinuousBuffer> create(size_t size, HailoRTDriver &driver);
+
+ static uint32_t get_buffer_size(uint32_t buffer_size);
+ // Get buffer size with the requirment that the amount of descriptors is a power of 2.
+ static uint32_t get_buffer_size_desc_power2(uint32_t buffer_size);
+
+ ContinuousBuffer(const ContinuousBuffer &) = delete;
+ ContinuousBuffer& operator=(const ContinuousBuffer &) = delete;
+ ContinuousBuffer& operator=(ContinuousBuffer &&) = delete;
+
+ virtual ~ContinuousBuffer();
+
+ ContinuousBuffer(ContinuousBuffer &&other) noexcept :
+ VdmaBuffer(std::move(other)),
+ m_size(other.m_size),
+ m_driver(other.m_driver),
+ m_handle(std::exchange(other.m_handle, 0)),
+ m_dma_address(std::exchange(other.m_dma_address, 0)),
+ m_mmap(std::move(other.m_mmap))
+ {}
+
+ virtual Type type() const override
+ {
+ return Type::CONTINUOUS;
+ }
+
+ virtual size_t size() const override;
+ virtual uint64_t dma_address() const override;
+ virtual uint16_t desc_page_size() const override;
+ virtual uint32_t descs_count() const override;
+
+ // Not used in this flow
+ virtual ExpectedRef<VdmaDescriptorList> get_desc_list() override
+ {
+ LOGGER__ERROR("Can't get descriptor list on continuous buffer");
+ return make_unexpected(HAILO_INVALID_OPERATION);
+ }
+
+ virtual hailo_status read(void *buf_dst, size_t count, size_t offset) override;
+ virtual hailo_status write(const void *buf_src, size_t count, size_t offset) override;
+
+ virtual Expected<uint32_t> program_descriptors(size_t transfer_size, VdmaInterruptsDomain first_desc_interrupts_domain,
+ VdmaInterruptsDomain last_desc_interrupts_domain, size_t desc_offset, bool is_circular) override;
+ virtual hailo_status reprogram_device_interrupts_for_end_of_batch(size_t transfer_size, uint16_t batch_size,
+ VdmaInterruptsDomain new_interrupts_domain) override;
+
+private:
+ ContinuousBuffer(size_t size, HailoRTDriver &driver, uintptr_t handle, uint64_t dma_address,
+ MmapBuffer<void> &&mmap);
+
+ const size_t m_size;
+ HailoRTDriver &m_driver;
+ uintptr_t m_handle;
+ uint64_t m_dma_address;
+ MmapBuffer<void> m_mmap;
+};
+
+}; /* namespace vdma */
+}; /* namespace hailort */
+
+#endif /* _HAILO_VDMA_CONTINUOUS_BUFFER_HPP_ */
--- /dev/null
+#include "mapped_buffer.hpp"
+#include "microprofile.h"
+
+namespace hailort {
+namespace vdma {
+
+Expected<MappedBuffer> MappedBuffer::create(size_t required_size, HailoRTDriver::DmaDirection data_direction,
+ HailoRTDriver &driver)
+{
+ hailo_status status = HAILO_UNINITIALIZED;
+ MappedBuffer object(required_size, data_direction, driver, status);
+ if (HAILO_SUCCESS != status) {
+ return make_unexpected(status);
+ }
+
+ return object;
+}
+
+MappedBuffer::MappedBuffer(
+ size_t required_size, HailoRTDriver::DmaDirection data_direction, HailoRTDriver &driver, hailo_status &status)
+ : m_user_address(), m_size(required_size), m_driver(driver),
+ m_driver_buff_handle(HailoRTDriver::INVALID_DRIVER_BUFFER_HANDLE_VALUE)
+{
+ auto buffer = allocate_vdma_buffer(driver, required_size, m_driver_buff_handle);
+ if (! buffer) {
+ status = buffer.status();
+ return;
+ }
+
+ auto expected_handle = m_driver.vdma_buffer_map(buffer->get(), required_size, data_direction, m_driver_buff_handle);
+ if (!expected_handle) {
+ status = expected_handle.status();
+ return;
+ }
+
+ m_handle = expected_handle.release();
+ m_user_address = buffer.release();
+ status = HAILO_SUCCESS;
+}
+
+MappedBuffer::~MappedBuffer()
+{
+ if (m_user_address) {
+ m_driver.vdma_buffer_unmap(m_handle);
+
+ if (HailoRTDriver::INVALID_DRIVER_BUFFER_HANDLE_VALUE != m_driver_buff_handle) {
+ m_driver.vdma_low_memory_buffer_free(m_driver_buff_handle);
+ }
+ }
+}
+
+hailo_status MappedBuffer::write(const void *buf_src, size_t count, size_t offset)
+{
+ if ((count + offset) > m_size) {
+ LOGGER__ERROR("Requested size {} from offset {} is more than the MappedBuffer size {}", count, offset, m_size);
+ return HAILO_INSUFFICIENT_BUFFER;
+ }
+
+ if (count > 0) {
+ auto dst_vdma_address = (uint8_t*)m_user_address.get() + offset;
+ memcpy(dst_vdma_address, buf_src, count);
+
+ auto status = m_driver.vdma_buffer_sync(m_handle, HailoRTDriver::DmaDirection::H2D, dst_vdma_address, count);
+ if (HAILO_SUCCESS != status) {
+ LOGGER__ERROR("Failed synching vdma buffer on write");
+ return status;
+ }
+ }
+
+ return HAILO_SUCCESS;
+}
+
+hailo_status MappedBuffer::read(void *buf_dst, size_t count, size_t offset)
+{
+ if ((count + offset) > m_size) {
+ LOGGER__ERROR("Requested size {} from offset {} is more than the MappedBuffer size {}", count, offset, m_size);
+ return HAILO_INSUFFICIENT_BUFFER;
+ }
+
+ if (count > 0) {
+ auto dst_vdma_address = (uint8_t*)m_user_address.get() + offset;
+ auto status = m_driver.vdma_buffer_sync(m_handle, HailoRTDriver::DmaDirection::D2H, dst_vdma_address, count);
+ if (HAILO_SUCCESS != status) {
+ LOGGER__ERROR("Failed synching vdma buffer on read");
+ return status;
+ }
+
+ memcpy(buf_dst, dst_vdma_address, count);
+ }
+
+ return HAILO_SUCCESS;
+}
+
+hailo_status MappedBuffer::write_cyclic(const void *buf_src, size_t count, size_t offset)
+{
+ MICROPROFILE_SCOPEI("vDMA", "Write buffer", 0);
+ if (count > m_size) {
+ LOGGER__ERROR("Requested size({}) is more than the MappedBuffer size {}", count, m_size);
+ return HAILO_INSUFFICIENT_BUFFER;
+ }
+
+ auto size_to_end = m_size - offset;
+ auto copy_size = std::min(size_to_end, count);
+ auto status = write(buf_src, copy_size, offset);
+ if (HAILO_SUCCESS != status) {
+ return status;
+ }
+
+ auto remaining_size = count - copy_size;
+ if (remaining_size > 0) {
+ status = write((uint8_t*)buf_src + copy_size, remaining_size, 0);
+ if (HAILO_SUCCESS != status) {
+ return status;
+ }
+ }
+
+ return HAILO_SUCCESS;
+}
+
+hailo_status MappedBuffer::read_cyclic(void *buf_dst, size_t count, size_t offset)
+{
+ MICROPROFILE_SCOPEI("vDMA", "Read buffer", 0);
+ if (count > m_size) {
+ LOGGER__ERROR("Requested size({}) is more than the MappedBuffer size {}", count, m_size);
+ return HAILO_INSUFFICIENT_BUFFER;
+ }
+
+ auto size_to_end = m_size - offset;
+ auto copy_size = std::min(size_to_end, count);
+ auto status = read(buf_dst, copy_size, offset);
+ if (HAILO_SUCCESS != status) {
+ return status;
+ }
+
+ auto remaining_size = count - copy_size;
+ if (remaining_size > 0) {
+ status = read((uint8_t*)buf_dst + copy_size, remaining_size, 0);
+ if (HAILO_SUCCESS != status) {
+ return status;
+ }
+ }
+
+ return HAILO_SUCCESS;
+}
+
+Expected<MmapBuffer<void>> MappedBuffer::allocate_vdma_buffer(HailoRTDriver &driver, size_t required_size,
+ uintptr_t &driver_buff_handle)
+{
+ // Check if driver should be allocated from driver or from user
+ if (driver.allocate_driver_buffer()) {
+ auto driver_buffer_handle = driver.vdma_low_memory_buffer_alloc(required_size);
+ CHECK_EXPECTED(driver_buffer_handle);
+
+ driver_buff_handle = driver_buffer_handle.release();
+
+ return MmapBuffer<void>::create_file_map(required_size, driver.fd(), driver_buff_handle);
+ }
+ else {
+ return MmapBuffer<void>::create_shared_memory(required_size);
+ }
+}
+
+} /* namespace vdma */
+} /* namespace hailort */
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file mapped_buffer.hpp
+ * @brief The mapped buffer that is continuous in virtual memory, but not on physical memory.
+ * We map the buffer to the IOMMU.
+ *
+ * The buffer can be used only with the help of a descriptors list that contains pointers to a physical
+ * continuous "dma pages".
+ *
+ * There are 2 options to allocated the buffer:
+ * 1. User mode allocation - the user mode calls `malloc` or `mmap` to allocate the buffer, then
+ * using HailoRTDriver we map the driver to the IOMMU (and pin the pages to avoid pagigs).
+ * This is the default option
+ * 2. Kernel mode allocation - on some systems, the user mode doesn't allocate the memory in a "dma-able" address,
+ * so we need to allocate the pages in driver.
+ **/
+
+#ifndef _HAILO_VDMA_MAPPED_BUFFER_HPP_
+#define _HAILO_VDMA_MAPPED_BUFFER_HPP_
+
+#include "os/mmap_buffer.hpp"
+#include "os/hailort_driver.hpp"
+#include "hailo/expected.hpp"
+
+namespace hailort {
+namespace vdma {
+
+class MappedBuffer final
+{
+public:
+ static Expected<MappedBuffer> create(size_t required_size, HailoRTDriver::DmaDirection data_direction,
+ HailoRTDriver &driver);
+
+ MappedBuffer(size_t required_size, HailoRTDriver::DmaDirection data_direction,
+ HailoRTDriver &driver, hailo_status &status);
+ ~MappedBuffer();
+
+ MappedBuffer(const MappedBuffer &other) = delete;
+ MappedBuffer &operator=(const MappedBuffer &other) = delete;
+ MappedBuffer(MappedBuffer &&other) noexcept = default;
+ MappedBuffer &operator=(MappedBuffer &&other) = delete;
+
+ void *user_address() { return m_user_address.get(); }
+ size_t handle() { return m_handle; }
+ size_t size() const { return m_size; }
+
+ /**
+ * Copy data from buf_src parameter to this MappedBuffer.
+ *
+ * @note (offset + count) MUST be smaller than this MappedBuffer size
+ *
+ * @param[in] buf_src The buffer to copy the data from
+ * @param[in] count Number of bytes to copy from buf_src
+ * @param[in] offset The offset relative to this MappedBuffer to copy the data to
+ */
+ hailo_status write(const void *buf_src, size_t count, size_t offset);
+
+ /**
+ * Copy data from this MappedBuffer to buf_dst.
+ *
+ * @note (offset + count) MUST be smaller than this MappedBuffer size
+ *
+ * @param[out] buf_dst The buffer to copy the data to
+ * @param[in] count Number of bytes to copy to buf_dst
+ * @param[in] offset The offset relative to this MappedBuffer to copy the data from
+ */
+ hailo_status read(void *buf_dst, size_t count, size_t offset);
+
+ /**
+ * Copy data from buf_src parameter to this MappedBuffer.
+ *
+ * Similar to 'write' but if (offset + count) is larger than the MappedBuffer size, the copy continues
+ * from the start of the MappedBuffer.
+ *
+ * @note count MUST be smaller than this MappedBuffer size
+ *
+ * @param[in] buf_src The buffer to copy the data from
+ * @param[in] count Number of bytes to copy from buf_src
+ * @param[in] offset The offset relative to this MappedBuffer to copy the data to
+ */
+ hailo_status write_cyclic(const void *buf_src, size_t count, size_t offset);
+
+ /**
+ * Copy data from this MappedBuffer to buf_dst.
+ *
+ * Similar to 'read' but if (offset + count) is larger than the MappedBuffer size, the copy continues
+ * from the start of the MappedBuffer.
+ *
+ * @note count MUST be smaller than this MappedBuffer size
+ *
+ * @param[out] buf_dst The buffer to copy the data to
+ * @param[in] count Number of bytes to copy to buf_dst
+ * @param[in] offset The offset relative to this MappedBuffer to copy the data from
+ */
+ hailo_status read_cyclic(void *buf_dst, size_t count, size_t offset);
+
+private:
+
+ static Expected<MmapBuffer<void>> allocate_vdma_buffer(HailoRTDriver &driver, size_t required_size,
+ uintptr_t &driver_buff_handle);
+
+ MmapBuffer<void> m_user_address;
+ HailoRTDriver::VdmaBufferHandle m_handle;
+ size_t m_size;
+ HailoRTDriver &m_driver;
+ uintptr_t m_driver_buff_handle;
+};
+
+} /* namespace vdma */
+} /* namespace hailort */
+
+#endif /* _HAILO_VDMA_MAPPED_BUFFER_HPP_ */
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file vdma_sg_buffer.cpp
+ * @brief Scatter-gather vdma buffer.
+ **/
+
+#include "sg_buffer.hpp"
+
+namespace hailort {
+namespace vdma {
+
+Expected<SgBuffer> SgBuffer::create(HailoRTDriver &driver, uint32_t desc_count, uint16_t desc_page_size,
+ HailoRTDriver::DmaDirection data_direction, uint8_t channel_index)
+{
+ auto desc_list = VdmaDescriptorList::create(desc_count, desc_page_size, driver);
+ CHECK_EXPECTED(desc_list);
+
+ assert((desc_count * desc_page_size) <= std::numeric_limits<uint32_t>::max());
+ auto mapped_buffer = MappedBuffer::create(desc_count * desc_page_size, data_direction, driver);
+ CHECK_EXPECTED(mapped_buffer);
+
+ auto status = desc_list->configure_to_use_buffer(mapped_buffer.value(), channel_index);
+ CHECK_SUCCESS_AS_EXPECTED(status);
+
+ return SgBuffer(desc_list.release(), mapped_buffer.release());
+}
+
+size_t SgBuffer::size() const
+{
+ return m_mapped_buffer.size();
+}
+
+uint64_t SgBuffer::dma_address() const
+{
+ return m_desc_list.dma_address();
+}
+
+uint16_t SgBuffer::desc_page_size() const
+{
+ return m_desc_list.desc_page_size();
+}
+
+uint32_t SgBuffer::descs_count() const
+{
+ return (uint32_t)m_desc_list.count();
+}
+
+uint8_t SgBuffer::depth() const
+{
+ return m_desc_list.depth();
+}
+
+ExpectedRef<VdmaDescriptorList> SgBuffer::get_desc_list()
+{
+ return std::ref(m_desc_list);
+}
+
+hailo_status SgBuffer::read(void *buf_dst, size_t count, size_t offset)
+{
+ return m_mapped_buffer.read(buf_dst, count, offset);
+}
+
+hailo_status SgBuffer::write(const void *buf_src, size_t count, size_t offset)
+{
+ return m_mapped_buffer.write(buf_src, count, offset);
+}
+
+Expected<uint32_t> SgBuffer::program_descriptors(size_t transfer_size, VdmaInterruptsDomain first_desc_interrupts_domain,
+ VdmaInterruptsDomain last_desc_interrupts_domain, size_t desc_offset, bool is_circular)
+{
+ return m_desc_list.program_descriptors(transfer_size, first_desc_interrupts_domain, last_desc_interrupts_domain,
+ desc_offset, is_circular);
+}
+
+hailo_status SgBuffer::reprogram_device_interrupts_for_end_of_batch(size_t transfer_size, uint16_t batch_size,
+ VdmaInterruptsDomain new_interrupts_domain)
+{
+ const auto desc_per_transfer = m_desc_list.descriptors_in_buffer(transfer_size);
+ const auto num_desc_in_batch = desc_per_transfer * batch_size;
+ const auto last_desc_index_in_batch = num_desc_in_batch - 1;
+ return m_desc_list.reprogram_descriptor_interrupts_domain(last_desc_index_in_batch, new_interrupts_domain);
+}
+
+}
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)
+ **/
+/**
+ * @file sg_buffer.hpp
+ * @brief Scatter-gather vdma buffer, from the user-mode point of view the buffer is continuous,
+ * but not from the physical-memory point of view.
+ * The sg buffer contains 2 parts:
+ * - MappedBuffer - the actual buffer stores the data.
+ * - Descriptors list - each descritpor points to a single "dma page" in the MappedBuffer.
+ * The hw accept the descriptors list address and parses it to get the actual data.
+ **/
+
+#ifndef _HAILO_VDMA_SG_BUFFER_HPP_
+#define _HAILO_VDMA_SG_BUFFER_HPP_
+
+#include "os/hailort_driver.hpp"
+#include "vdma/vdma_buffer.hpp"
+#include "vdma_descriptor_list.hpp"
+#include "vdma/mapped_buffer.hpp"
+
+namespace hailort {
+namespace vdma {
+
+class SgBuffer final : public VdmaBuffer {
+public:
+ static Expected<SgBuffer> create(HailoRTDriver &driver, uint32_t desc_count, uint16_t desc_page_size,
+ HailoRTDriver::DmaDirection data_direction, uint8_t channel_index = 0);
+
+ virtual ~SgBuffer() = default;
+
+ SgBuffer(const SgBuffer &) = delete;
+ SgBuffer(SgBuffer &&) = default;
+ SgBuffer& operator=(const SgBuffer &) = delete;
+ SgBuffer& operator=(SgBuffer &&) = delete;
+
+ virtual Type type() const override
+ {
+ return Type::SCATTER_GATHER;
+ }
+
+ virtual size_t size() const override;
+ virtual uint64_t dma_address() const override;
+ virtual uint16_t desc_page_size() const override;
+ virtual uint32_t descs_count() const override;
+ uint8_t depth() const;
+
+ // Should be only used for host managed ddr buffer, in the future this function may return nullptr (on CCB
+ // case where there is no descriptors list)
+ virtual ExpectedRef<VdmaDescriptorList> get_desc_list() override;
+
+ virtual hailo_status read(void *buf_dst, size_t count, size_t offset) override;
+ virtual hailo_status write(const void *buf_src, size_t count, size_t offset) override;
+
+ virtual Expected<uint32_t> program_descriptors(size_t transfer_size, VdmaInterruptsDomain first_desc_interrupts_domain,
+ VdmaInterruptsDomain last_desc_interrupts_domain, size_t desc_offset, bool is_circular) override;
+ virtual hailo_status reprogram_device_interrupts_for_end_of_batch(size_t transfer_size, uint16_t batch_size,
+ VdmaInterruptsDomain new_interrupts_domain) override;
+
+private:
+ SgBuffer(VdmaDescriptorList &&desc_list, MappedBuffer &&mapped_buffer) :
+ m_desc_list(std::move(desc_list)),
+ m_mapped_buffer(std::move(mapped_buffer))
+ {}
+
+ VdmaDescriptorList m_desc_list;
+ MappedBuffer m_mapped_buffer;
+};
+
+} /* vdma */
+} /* hailort */
+
+#endif /* _HAILO_VDMA_SG_BUFFER_HPP_ */
--- /dev/null
+/**\r
+ * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.\r
+ * Distributed under the MIT license (https://opensource.org/licenses/MIT)\r
+ **/\r
+/**\r
+ * @file vdma_buffer.hpp\r
+ * @brief Abstract layer representing a vdma buffer (buffer that can be read/written to the device over vdma.)\r
+ * The buffer can be either non-continuous with attach descriptors list (SgBuffer) or continuous buffer.\r
+ **/\r
+\r
+#ifndef _HAILO_VDMA_VDMA_BUFFER_HPP_\r
+#define _HAILO_VDMA_VDMA_BUFFER_HPP_\r
+\r
+#include "os/hailort_driver.hpp"\r
+#include "vdma_descriptor_list.hpp"\r
+\r
+namespace hailort {\r
+namespace vdma {\r
+\r
+class VdmaBuffer {\r
+public:\r
+\r
+ enum class Type {\r
+ SCATTER_GATHER,\r
+ CONTINUOUS\r
+ };\r
+\r
+ virtual ~VdmaBuffer() = default;\r
+\r
+ VdmaBuffer() = default;\r
+ VdmaBuffer(const VdmaBuffer &) = delete;\r
+ VdmaBuffer(VdmaBuffer &&) = default;\r
+ VdmaBuffer& operator=(const VdmaBuffer &) = delete;\r
+ VdmaBuffer& operator=(VdmaBuffer &&) = delete;\r
+\r
+ virtual Type type() const = 0;\r
+ virtual size_t size() const = 0;\r
+ virtual uint64_t dma_address() const = 0;\r
+ virtual uint16_t desc_page_size() const = 0;\r
+ virtual uint32_t descs_count() const = 0;\r
+\r
+ uint32_t descriptors_in_buffer(size_t buffer_size) const\r
+ {\r
+ assert(buffer_size < std::numeric_limits<uint32_t>::max());\r
+ const auto page_size = desc_page_size();\r
+ return static_cast<uint32_t>(DESCRIPTORS_IN_BUFFER(buffer_size, page_size));\r
+ }\r
+\r
+ // If there's no descriptor list then Unexpected(HAILO_INVALID_OPERATION) will be returned\r
+ // (E.g. for CCB, where there is no descriptors list)\r
+ virtual ExpectedRef<VdmaDescriptorList> get_desc_list() = 0;\r
+\r
+ virtual hailo_status read(void *buf_dst, size_t count, size_t offset) = 0;\r
+ virtual hailo_status write(const void *buf_src, size_t count, size_t offset) = 0;\r
+\r
+ virtual Expected<uint32_t> program_descriptors(size_t transfer_size, VdmaInterruptsDomain first_desc_interrupts_domain,\r
+ VdmaInterruptsDomain last_desc_interrupts_domain, size_t desc_offset, bool is_circular) = 0;\r
+ virtual hailo_status reprogram_device_interrupts_for_end_of_batch(size_t transfer_size, uint16_t batch_size,\r
+ VdmaInterruptsDomain new_interrupts_domain) = 0;\r
+};\r
+\r
+} /* vdma */\r
+} /* hailort */\r
+\r
+#endif /* _HAILO_VDMA_VDMA_BUFFER_HPP_ */\r
+++ /dev/null
-#include "vdma_buffer.hpp"
-
-namespace hailort
-{
-
-Expected<VdmaBuffer> VdmaBuffer::create(size_t required_size, HailoRTDriver::DmaDirection data_direction,
- HailoRTDriver &driver)
-{
- hailo_status status = HAILO_UNINITIALIZED;
- VdmaBuffer object(required_size, data_direction, driver, status);
- if (HAILO_SUCCESS != status) {
- return make_unexpected(status);
- }
-
- return object;
-}
-
-VdmaBuffer::VdmaBuffer(
- size_t required_size, HailoRTDriver::DmaDirection data_direction, HailoRTDriver &driver, hailo_status &status)
- : m_user_address(), m_size(required_size), m_driver(driver),
- m_driver_buff_handle(HailoRTDriver::INVALID_DRIVER_BUFFER_HANDLE_VALUE)
-{
- auto buffer = allocate_vdma_buffer(driver, required_size, m_driver_buff_handle);
- if (! buffer) {
- status = buffer.status();
- return;
- }
-
- auto expected_handle = m_driver.vdma_buffer_map(buffer->get(), required_size, data_direction, m_driver_buff_handle);
- if (!expected_handle) {
- status = expected_handle.status();
- return;
- }
-
- m_handle = expected_handle.release();
- m_user_address = buffer.release();
- status = HAILO_SUCCESS;
-}
-
-VdmaBuffer::~VdmaBuffer()
-{
- if (m_user_address) {
- m_driver.vdma_buffer_unmap(m_handle);
-
- if (HailoRTDriver::INVALID_DRIVER_BUFFER_HANDLE_VALUE != m_driver_buff_handle) {
- m_driver.vdma_low_memory_buffer_free(m_driver_buff_handle);
- }
- }
-}
-
-hailo_status VdmaBuffer::write(const void *buf_src, size_t count, size_t offset)
-{
- if ((count + offset) > m_size) {
- LOGGER__ERROR("Requested size {} from offset {} is more than the VdmaBuffer size {}", count, offset, m_size);
- return HAILO_INSUFFICIENT_BUFFER;
- }
-
- if (count > 0) {
- auto dst_vdma_address = (uint8_t*)m_user_address.get() + offset;
- memcpy(dst_vdma_address, buf_src, count);
-
- auto status = m_driver.vdma_buffer_sync(m_handle, HailoRTDriver::DmaDirection::H2D, dst_vdma_address, count);
- if (HAILO_SUCCESS != status) {
- LOGGER__ERROR("Failed synching vdma buffer on write");
- return status;
- }
- }
-
- return HAILO_SUCCESS;
-}
-
-hailo_status VdmaBuffer::read(void *buf_dst, size_t count, size_t offset)
-{
- if ((count + offset) > m_size) {
- LOGGER__ERROR("Requested size {} from offset {} is more than the VdmaBuffer size {}", count, offset, m_size);
- return HAILO_INSUFFICIENT_BUFFER;
- }
-
- if (count > 0) {
- auto dst_vdma_address = (uint8_t*)m_user_address.get() + offset;
- auto status = m_driver.vdma_buffer_sync(m_handle, HailoRTDriver::DmaDirection::D2H, dst_vdma_address, count);
- if (HAILO_SUCCESS != status) {
- LOGGER__ERROR("Failed synching vdma buffer on read");
- return status;
- }
-
- memcpy(buf_dst, dst_vdma_address, count);
- }
-
- return HAILO_SUCCESS;
-}
-
-hailo_status VdmaBuffer::write_cyclic(const void *buf_src, size_t count, size_t offset)
-{
- if (count > m_size) {
- LOGGER__ERROR("Requested size({}) is more than the VdmaBuffer size {}", count, m_size);
- return HAILO_INSUFFICIENT_BUFFER;
- }
-
- auto size_to_end = m_size - offset;
- auto copy_size = std::min(size_to_end, count);
- auto status = write(buf_src, copy_size, offset);
- if (HAILO_SUCCESS != status) {
- return status;
- }
-
- auto remaining_size = count - copy_size;
- if (remaining_size > 0) {
- status = write((uint8_t*)buf_src + copy_size, remaining_size, 0);
- if (HAILO_SUCCESS != status) {
- return status;
- }
- }
-
- return HAILO_SUCCESS;
-}
-
-hailo_status VdmaBuffer::read_cyclic(void *buf_dst, size_t count, size_t offset)
-{
- if (count > m_size) {
- LOGGER__ERROR("Requested size({}) is more than the VdmaBuffer size {}", count, m_size);
- return HAILO_INSUFFICIENT_BUFFER;
- }
-
- auto size_to_end = m_size - offset;
- auto copy_size = std::min(size_to_end, count);
- auto status = read(buf_dst, copy_size, offset);
- if (HAILO_SUCCESS != status) {
- return status;
- }
-
- auto remaining_size = count - copy_size;
- if (remaining_size > 0) {
- status = read((uint8_t*)buf_dst + copy_size, remaining_size, 0);
- if (HAILO_SUCCESS != status) {
- return status;
- }
- }
-
- return HAILO_SUCCESS;
-}
-
-Expected<MmapBuffer<void>> VdmaBuffer::allocate_vdma_buffer(HailoRTDriver &driver, size_t required_size,
- uintptr_t &driver_buff_handle)
-{
- // Check if driver should be allocated from driver or from user
- if (driver.allocate_driver_buffer()) {
- auto driver_buffer_handle = driver.vdma_low_memory_buffer_alloc(required_size);
- CHECK_EXPECTED(driver_buffer_handle);
-
- driver_buff_handle = driver_buffer_handle.release();
-
- return MmapBuffer<void>::create_file_map(required_size, driver.fd(), driver_buff_handle);
- }
- else {
- return MmapBuffer<void>::create_shared_memory(required_size);
- }
-}
-
-} /* namespace hailort */
+++ /dev/null
-/**
- * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
- * Distributed under the MIT license (https://opensource.org/licenses/MIT)
- **/
-/**
- * @file vdma_buffer.hpp
- * @brief Provides a buffer that can be used for VDMA
- *
- **/
-
-#ifndef _HAILO_VDMA_BUFFER_HPP_
-#define _HAILO_VDMA_BUFFER_HPP_
-
-#include "os/mmap_buffer.hpp"
-#include "os/hailort_driver.hpp"
-#include "hailo/expected.hpp"
-
-namespace hailort
-{
-
-class VdmaBuffer final
-{
-public:
- static Expected<VdmaBuffer> create(size_t required_size, HailoRTDriver::DmaDirection data_direction,
- HailoRTDriver &driver);
-
- VdmaBuffer(size_t required_size, HailoRTDriver::DmaDirection data_direction,
- HailoRTDriver &driver, hailo_status &status);
- ~VdmaBuffer();
-
- VdmaBuffer(const VdmaBuffer &other) = delete;
- VdmaBuffer &operator=(const VdmaBuffer &other) = delete;
- VdmaBuffer(VdmaBuffer &&other) noexcept = default;
- VdmaBuffer &operator=(VdmaBuffer &&other) = delete;
-
- void *user_address() { return m_user_address.get(); }
- size_t handle() { return m_handle; }
- size_t size() const { return m_size; }
-
- /**
- * Copy data from buf_src parameter to this VdmaBuffer.
- *
- * @note (offset + count) MUST be smaller than this VdmaBuffer size
- *
- * @param[in] buf_src The buffer to copy the data from
- * @param[in] count Number of bytes to copy from buf_src
- * @param[in] offset The offset relative to this VdmaBuffer to copy the data to
- */
- hailo_status write(const void *buf_src, size_t count, size_t offset);
-
- /**
- * Copy data from this VdmaBuffer to buf_dst.
- *
- * @note (offset + count) MUST be smaller than this VdmaBuffer size
- *
- * @param[out] buf_dst The buffer to copy the data to
- * @param[in] count Number of bytes to copy to buf_dst
- * @param[in] offset The offset relative to this VdmaBuffer to copy the data from
- */
- hailo_status read(void *buf_dst, size_t count, size_t offset);
-
- /**
- * Copy data from buf_src parameter to this VdmaBuffer.
- *
- * Similar to 'write' but if (offset + count) is larger than the VdmaBuffer size, the copy continues
- * from the start of the VdmaBuffer.
- *
- * @note count MUST be smaller than this VdmaBuffer size
- *
- * @param[in] buf_src The buffer to copy the data from
- * @param[in] count Number of bytes to copy from buf_src
- * @param[in] offset The offset relative to this VdmaBuffer to copy the data to
- */
- hailo_status write_cyclic(const void *buf_src, size_t count, size_t offset);
-
- /**
- * Copy data from this VdmaBuffer to buf_dst.
- *
- * Similar to 'read' but if (offset + count) is larger than the VdmaBuffer size, the copy continues
- * from the start of the VdmaBuffer.
- *
- * @note count MUST be smaller than this VdmaBuffer size
- *
- * @param[out] buf_dst The buffer to copy the data to
- * @param[in] count Number of bytes to copy to buf_dst
- * @param[in] offset The offset relative to this VdmaBuffer to copy the data from
- */
- hailo_status read_cyclic(void *buf_dst, size_t count, size_t offset);
-
-private:
-
- static Expected<MmapBuffer<void>> allocate_vdma_buffer(HailoRTDriver &driver, size_t required_size,
- uintptr_t &driver_buff_handle);
-
- MmapBuffer<void> m_user_address;
- HailoRTDriver::VdmaBufferHandle m_handle;
- size_t m_size;
- HailoRTDriver &m_driver;
- uintptr_t m_driver_buff_handle;
-};
-
-} /* namespace hailort */
-
-#endif /* _HAILO_VDMA_BUFFER_HPP_ */
\ No newline at end of file
#include "hw_consts.hpp"
#include "common/logger_macros.hpp"
#include "common/utils.hpp"
+#include "microprofile.h"
#include <list>
#include <chrono>
VdmaChannel::VdmaChannel(uint8_t channel_index, Direction direction, HailoRTDriver &driver,
uint32_t stream_index, LatencyMeterPtr latency_meter, uint16_t desc_page_size, uint16_t transfers_per_axi_intr,
hailo_status &status)
- : channel_index(channel_index), m_direction(direction), m_driver(driver),
+ : m_channel_index(channel_index), m_direction(direction), m_driver(driver),
m_host_registers(driver, channel_index, direction),
m_device_registers(driver, channel_index, other_direction(direction)), m_desc_page_size(desc_page_size),
m_stream_index(stream_index), m_latency_meter(latency_meter), m_channel_enabled(false),
- m_transfers_per_axi_intr(transfers_per_axi_intr)
+ m_transfers_per_axi_intr(transfers_per_axi_intr), m_pending_buffers_sizes(0), m_pending_num_avail_offset(0), m_is_waiting_for_channel_completion(false),
+ m_is_aborted(false)
{
// channel index invalid
if (channel_index >= MAX_HOST_CHANNELS_COUNT) {
}
VdmaChannel::VdmaChannel(VdmaChannel &&other) noexcept:
-channel_index(other.channel_index),
+m_channel_index(other.m_channel_index),
m_direction(other.m_direction),
m_driver(other.m_driver),
m_host_registers(std::move(other.m_host_registers)),
m_state(std::move(other.m_state)),
m_channel_handle(std::move(other.m_channel_handle)),
m_channel_enabled(std::exchange(other.m_channel_enabled, false)),
- m_transfers_per_axi_intr(std::move(other.m_transfers_per_axi_intr))
+ m_transfers_per_axi_intr(std::move(other.m_transfers_per_axi_intr)),
+ m_pending_buffers_sizes(std::move(other.m_pending_buffers_sizes)),
+ m_pending_num_avail_offset(std::move(other.m_pending_num_avail_offset)),
+ m_is_waiting_for_channel_completion(other.m_is_waiting_for_channel_completion.load()),
+ m_is_aborted(std::move(other.m_is_aborted))
{}
hailo_status VdmaChannel::stop_channel()
if (HailoRTDriver::INVALID_VDMA_CHANNEL_HANDLE != *m_channel_handle) {
// The driver also stops the channels
const auto status = unregister_fw_controlled_channel();
- CHECK_SUCCESS(status, "Failed to disable channel {}", channel_index);
+ CHECK_SUCCESS(status, "Failed to disable channel {}", m_channel_index);
+ }
+
+ if (m_state) {
+ std::lock_guard<State> state_guard(*m_state);
+ reset_internal_counters();
}
return HAILO_SUCCESS;
hailo_status VdmaChannel::abort()
{
- return m_driver.vdma_channel_abort(channel_index, *m_channel_handle);
+ m_is_aborted = true;
+ m_can_write_buffer_cv.notify_one();
+ return m_driver.vdma_channel_abort(m_channel_index, *m_channel_handle);
}
hailo_status VdmaChannel::clear_abort()
{
- return m_driver.vdma_channel_clear_abort(channel_index, *m_channel_handle);
+ m_is_aborted = false;
+ return m_driver.vdma_channel_clear_abort(m_channel_index, *m_channel_handle);
}
hailo_status VdmaChannel::prepare_d2h_pending_descriptors(uint32_t descs_count, uint32_t transfer_size)
for (uint32_t i = 0; i < transfers_count; i++) {
/* Provide FW interrupt only in the end of the last transfer in the batch */
auto last_desc_interrutps_domain =
- (static_cast<uint32_t>(m_transfers_per_axi_intr -1) == (i % m_transfers_per_axi_intr)) ?
+ (static_cast<uint32_t>(m_transfers_per_axi_intr - 1) == (i % m_transfers_per_axi_intr)) ?
VdmaInterruptsDomain::BOTH : VdmaInterruptsDomain::HOST;
auto status = prepare_descriptors(transfer_size, first_desc_interrupts_domain, last_desc_interrutps_domain);
CHECK_SUCCESS(status, "Failed prepare desc status={}", status);
#endif
m_state = state.release();
+ m_pending_buffers_sizes = CircularArray<size_t>(descs_count);
// If measuring latency, max_active_transfer is limited to 16 (see hailort_driver.hpp doc for further information)
int pending_buffers_size = (nullptr == m_latency_meter) ? static_cast<int>(m_state->m_pending_buffers.size()) :
/* descriptor buffer must be allocated */
assert(m_descriptors_buffer);
assert(m_state);
-
std::lock_guard<State> state_guard(*m_state);
-
reset_internal_counters();
auto status = start_channel(*m_descriptors_buffer);
- CHECK_SUCCESS(status, "failed to start channel {}", channel_index);
+ CHECK_SUCCESS(status, "failed to start channel {}", m_channel_index);
if ((Direction::D2H == m_direction) && (transfer_size != 0)) {
auto descs_count = CB_SIZE(m_state->m_descs);
}
return status;
}
+
return HAILO_SUCCESS;
}
hailo_status VdmaChannel::transfer(void *buf, size_t count)
{
- if ((nullptr == buf) || (0 == count)) {
- return HAILO_INVALID_ARGUMENT;
- }
-
- if (!m_mapped_user_buffer) {
- LOGGER__ERROR("Transfer called without allocating buffers");
- return HAILO_INVALID_OPERATION;
- }
+ CHECK((nullptr != buf) && (0 < count), HAILO_INVALID_ARGUMENT);
+ CHECK(nullptr != m_mapped_user_buffer, HAILO_INVALID_OPERATION, "Transfer called without allocating buffers");
hailo_status status = HAILO_UNINITIALIZED;
assert(m_state);
if (Direction::H2D == m_direction) {
status = transfer_h2d(buf, count);
if (HAILO_SUCCESS != status) {
- LOGGER__ERROR("Transfer failed for channel {}", channel_index);
+ LOGGER__ERROR("Transfer failed for channel {}", m_channel_index);
return status;
}
return HAILO_SUCCESS;
} else {
status = transfer_d2h(buf, count);
if (HAILO_SUCCESS != status) {
- LOGGER__ERROR("Transfer failed for channel {} status {}", channel_index, status);
+ LOGGER__ERROR("Transfer failed for channel {} status {}", m_channel_index, status);
return status;
}
return HAILO_SUCCESS;
return HAILO_SUCCESS;
}
-hailo_status VdmaChannel::flush(const std::chrono::milliseconds &timeout)
+hailo_status VdmaChannel::write_buffer_impl(const MemoryView &buffer)
+{
+ CHECK(nullptr != m_mapped_user_buffer, HAILO_INVALID_OPERATION, "Transfer called without allocating buffers");
+
+ size_t desired_desc_num = m_descriptors_buffer->descriptors_in_buffer(buffer.size());
+ uint32_t desc_avail = (get_num_available() + m_pending_num_avail_offset) & m_state->m_descs.size_mask;
+
+ assert(CB_AVAIL(m_state->m_descs, desc_avail, CB_TAIL(m_state->m_descs)) >= static_cast<uint16_t>(desired_desc_num));
+
+ /* Copy buffer into the PLDA data struct */
+ auto offset = desc_avail * m_desc_page_size;
+ auto status = m_mapped_user_buffer->write_cyclic(buffer.data(), buffer.size(), offset);
+ CHECK_SUCCESS(status);
+
+ m_pending_num_avail_offset = static_cast<uint16_t>(m_pending_num_avail_offset + desired_desc_num);
+
+ CHECK(!m_pending_buffers_sizes.full(), HAILO_INVALID_OPERATION, "Cannot add more pending buffers!");
+ m_pending_buffers_sizes.push_back(buffer.size());
+ return HAILO_SUCCESS;
+}
+
+hailo_status VdmaChannel::write_buffer(const MemoryView &buffer, std::chrono::milliseconds timeout)
{
assert(m_state);
+ std::unique_lock<State> state_guard(*m_state);
- if (Direction::D2H == m_direction) {
- // We are not buffering user data
- return HAILO_SUCCESS;
- }
+ hailo_status status = HAILO_UNINITIALIZED;
+ size_t desired_desc_num = m_descriptors_buffer->descriptors_in_buffer(buffer.size());
+ bool was_successful = m_can_write_buffer_cv.wait_for(state_guard, timeout, [this, &status, desired_desc_num] () {
+ if ((!m_channel_enabled) || (m_is_aborted)) {
+ status = HAILO_STREAM_INTERNAL_ABORT;
+ return true;
+ }
- if (!m_mapped_user_buffer) {
- LOGGER__ERROR("VdmaChannel::flush is called on a channel without allocated resources");
- return HAILO_INVALID_OPERATION;
+ uint32_t desc_avail = (get_num_available() + m_pending_num_avail_offset) & m_state->m_descs.size_mask;
+ int num_free = CB_AVAIL(m_state->m_descs, desc_avail, CB_TAIL(m_state->m_descs));
+ return (num_free >= static_cast<uint16_t>(desired_desc_num));
+ });
+ if (HAILO_STREAM_INTERNAL_ABORT == status) {
+ LOGGER__INFO("wait_for in write_buffer was aborted!");
+ return status;
}
+ CHECK(was_successful, HAILO_TIMEOUT, "Waiting for descriptors in write_buffer has reached a timeout!");
- return wait_for_condition([this] { return CB_HEAD(m_state->m_buffers) == CB_TAIL(m_state->m_buffers); }, timeout);
+ return write_buffer_impl(buffer);
}
-hailo_status VdmaChannel::transfer_h2d(void *buf, size_t count)
+hailo_status VdmaChannel::send_pending_buffer_impl()
{
- uint16_t descNum = 0;
- const uint16_t pageSize = m_desc_page_size;
- uint32_t desc_avail = 0;
- hailo_status status = HAILO_UNINITIALIZED;
+ CHECK(!m_pending_buffers_sizes.empty(), HAILO_INVALID_OPERATION, "There are no pending buffers to send!");
+
// For h2d, only the host need to get transfer done interrupts
VdmaInterruptsDomain last_desc_interrupts_domain = VdmaInterruptsDomain::HOST;
- // If we measure latecy, we need interrupt on the first descriptor
+ // If we measure latency, we need interrupt on the first descriptor
VdmaInterruptsDomain first_desc_interrupts_domain = (m_latency_meter != nullptr) ?
VdmaInterruptsDomain::HOST : VdmaInterruptsDomain::NONE;
- assert(buf != nullptr);
- assert(m_state);
+ auto status = prepare_descriptors(m_pending_buffers_sizes.front(), first_desc_interrupts_domain, last_desc_interrupts_domain);
+ CHECK_SUCCESS(status);
- desc_avail = get_num_available();
+ m_state->m_accumulated_transfers = (m_state->m_accumulated_transfers + 1) % m_transfers_per_axi_intr;
- /* calculate desired descriptors for the buffer */
- size_t desiredDescNum = ((count + pageSize - 1) / pageSize);
- if (desiredDescNum > UINT16_MAX) {
- return HAILO_OUT_OF_DESCRIPTORS;
+ size_t desired_desc_num = m_descriptors_buffer->descriptors_in_buffer(m_pending_buffers_sizes.front());
+ m_pending_num_avail_offset = static_cast<uint16_t>(m_pending_num_avail_offset - desired_desc_num);
+
+ m_pending_buffers_sizes.pop_front();
+
+ return HAILO_SUCCESS;
+}
+
+Expected<PendingBufferState> VdmaChannel::send_pending_buffer()
+{
+ size_t next_buffer_desc_num = 0;
+ {
+ assert(m_state);
+ std::lock_guard<State> state_guard(*m_state);
+
+ // Save before calling send_pending_buffer_impl because we pop from m_pending_buffers_sizes there
+ next_buffer_desc_num = m_descriptors_buffer->descriptors_in_buffer(m_pending_buffers_sizes.front());
+
+ auto status = send_pending_buffer_impl();
+ CHECK_SUCCESS_AS_EXPECTED(status);
}
- descNum = (uint16_t)(desiredDescNum);
- int num_available = desc_avail;
- int num_processed = CB_TAIL(m_state->m_descs);
- int num_free = CB_AVAIL(m_state->m_descs, num_available, num_processed);
- if (num_free < descNum) {
- return HAILO_OUT_OF_DESCRIPTORS;
+ m_can_write_buffer_cv.notify_one();
+
+ return PendingBufferState(*this, next_buffer_desc_num);
+}
+
+hailo_status PendingBufferState::finish(std::chrono::milliseconds timeout, std::unique_lock<std::mutex> &lock)
+{
+ unlock_guard<std::unique_lock<std::mutex>> unlock(lock);
+
+ while (true) {
+ {
+ std::lock_guard<VdmaChannel::State> state_guard(*m_vdma_channel.m_state);
+
+ // Make sure that only one thread is waiting for channel completion
+ if (m_vdma_channel.m_is_waiting_for_channel_completion) {
+ break;
+ }
+
+ // When all pending buffers have been sent but no buffers were processed yet (there are no free descriptors) we want to wait
+ // for channel completion to make free room to the next buffers
+ // TODO: This assumes the next buffer is the same size as the current one, so consider moving this to the write_buffer function
+ int num_free = CB_AVAIL(m_vdma_channel.m_state->m_descs, m_vdma_channel.get_num_available(), CB_TAIL(m_vdma_channel.m_state->m_descs));
+
+ // We use m_next_buffer_desc_num to check if the next buffer has enough descriptors
+ bool should_free_descs = (0 == m_vdma_channel.m_pending_num_avail_offset) && (num_free < static_cast<uint16_t>(m_next_buffer_desc_num));
+ m_vdma_channel.m_is_waiting_for_channel_completion = should_free_descs;
+ if (!should_free_descs) {
+ break;
+ }
+ }
+
+ auto status = m_vdma_channel.wait_for_channel_completion(timeout);
+ if (HAILO_STREAM_INTERNAL_ABORT == status) {
+ LOGGER__INFO("wait_for_channel_completion has failed with status=HAILO_STREAM_INTERNAL_ABORT");
+ return status;
+ }
+ CHECK_SUCCESS(status);
}
- /* Copy buffer into the PLDA data struct */
- auto offset = desc_avail * pageSize;
- status = m_mapped_user_buffer->write_cyclic(buf, count, offset);
- CHECK_SUCCESS(status);
+ return HAILO_SUCCESS;
+}
- status = prepare_descriptors(count, first_desc_interrupts_domain, last_desc_interrupts_domain);
+hailo_status VdmaChannel::flush(const std::chrono::milliseconds &timeout)
+{
+ assert(m_state);
+
+ if (Direction::D2H == m_direction) {
+ // We are not buffering user data
+ return HAILO_SUCCESS;
+ }
+
+ if (!m_mapped_user_buffer) {
+ LOGGER__ERROR("VdmaChannel::flush is called on a channel without allocated resources");
+ return HAILO_INVALID_OPERATION;
+ }
+
+ return wait_for_condition([this] { return CB_HEAD(m_state->m_buffers) == CB_TAIL(m_state->m_buffers); }, timeout);
+}
+
+hailo_status VdmaChannel::transfer_h2d(void *buf, size_t count)
+{
+ auto status = write_buffer_impl(MemoryView(buf, count));
CHECK_SUCCESS(status);
- m_state->m_accumulated_transfers = (m_state->m_accumulated_transfers + 1) % m_transfers_per_axi_intr;
+ status = send_pending_buffer_impl();
+ CHECK_SUCCESS(status);
return HAILO_SUCCESS;
}
m_state->m_accumulated_transfers = (m_state->m_accumulated_transfers + 1) % m_transfers_per_axi_intr;
return HAILO_SUCCESS;
-
}
uint16_t VdmaChannel::get_num_available()
auto hw_num_avail = m_host_registers.get_num_available();
assert(hw_num_avail);
// On case of channel aborted, the num_available is set to 0 (so we don't accept sync)
- assert((hw_num_avail.value() == num_available) || is_aborted().value());
+
+ auto is_aborted_exp = is_aborted();
+ assert(is_aborted_exp);
+
+ if ((HailoRTDriver::INVALID_VDMA_CHANNEL_HANDLE != *m_channel_handle) && !is_aborted_exp.value()) {
+ assert(hw_num_avail.value() == num_available);
+ }
#endif
return num_available;
}
return static_cast<uint16_t>(hw_num_processed.value() & m_state->m_descs.size_mask);
}
-Expected<uint16_t> VdmaChannel::get_hw_num_processed_ddr(uint32_t size_mask)
-{
- auto hw_num_processed = m_host_registers.get_num_processed();
- CHECK_EXPECTED(hw_num_processed, "Fail to read vdma num processed register");
-
- // Although the hw_num_processed should be a number between 0 and m_descs.size-1, if
- // m_desc.size < 0x10000 (the maximum desc size), the actual hw_num_processed is a number
- // between 1 and m_descs.size. Therefore the value can be m_descs.size, in this case we change it
- // to zero.
- return static_cast<uint16_t>(hw_num_processed.value() & size_mask);
-}
-
-hailo_status VdmaChannel::wait_channel_interrupts_for_ddr(const std::chrono::milliseconds &timeout)
-{
- auto irq_data = m_driver.wait_channel_interrupts(channel_index, *m_channel_handle, timeout);
- return irq_data.status();
-}
-
hailo_status VdmaChannel::set_num_avail_value(uint16_t new_value)
{
auto status = m_host_registers.set_num_available(new_value);
assert(hw_num_avail);
assert(hw_num_avail.value() == new_value);
#endif
-
return HAILO_SUCCESS;
}
-hailo_status VdmaChannel::inc_num_available_for_ddr(uint16_t value, uint32_t size_mask)
+hailo_status VdmaChannel::set_transfers_per_axi_intr(uint16_t transfers_per_axi_intr)
{
- //TODO: validate that count is added.
- auto num_available = m_host_registers.get_num_available();
- CHECK_EXPECTED_AS_STATUS(num_available, "Fail to read vdma num available register");
-
- uint16_t new_value = static_cast<uint16_t>((num_available.value() + value) & size_mask);
- return set_num_avail_value(new_value);
+ CHECK(0 != transfers_per_axi_intr, HAILO_INVALID_ARGUMENT, "Invalid transfers per axi interrupt");
+ m_transfers_per_axi_intr = transfers_per_axi_intr;
+ return HAILO_SUCCESS;
}
hailo_status VdmaChannel::inc_num_available(uint16_t value)
int num_available = get_num_available();
int num_processed = CB_TAIL(m_state->m_descs);
int num_free = CB_AVAIL(m_state->m_descs, num_available, num_processed);
- uint16_t hw_num_avail = 0;
-
- (void) hw_num_avail;
if (value > num_free) {
return HAILO_OUT_OF_DESCRIPTORS;
}
hailo_status VdmaChannel::unregister_fw_controlled_channel()
{
- auto status = m_driver.vdma_channel_disable(channel_index, *m_channel_handle);
+ auto status = m_driver.vdma_channel_disable(m_channel_index, *m_channel_handle);
*m_channel_handle = HailoRTDriver::INVALID_VDMA_CHANNEL_HANDLE;
- CHECK_SUCCESS(status, "Failed to disable channel {}", channel_index);
+ CHECK_SUCCESS(status, "Failed to disable channel {}", m_channel_index);
return HAILO_SUCCESS;
}
{
const bool measure_latency = (nullptr != m_latency_meter);
const uintptr_t desc_handle = desc_list_handle;
- auto channel_handle = m_driver.vdma_channel_enable(channel_index, m_direction, desc_handle, measure_latency);
- CHECK_EXPECTED_AS_STATUS(channel_handle, "Failed to enable channel {}", channel_index);
+ auto channel_handle = m_driver.vdma_channel_enable(m_channel_index, m_direction, desc_handle, measure_latency);
+ CHECK_EXPECTED_AS_STATUS(channel_handle, "Failed to enable channel {}", m_channel_index);
*m_channel_handle = channel_handle.release();
return HAILO_SUCCESS;
assert(is_aborted());
auto status = register_channel_to_driver(desc_list.handle());
- CHECK_SUCCESS(status, "Failed to enable channel {}", channel_index);
+ CHECK_SUCCESS(status, "Failed to enable channel {}", m_channel_index);
return HAILO_SUCCESS;
}
}
}
-hailo_status VdmaChannel::allocate_buffer(const size_t buffer_size)
+hailo_status VdmaChannel::allocate_buffer(const uint32_t buffer_size)
{
assert((buffer_size % m_desc_page_size) == 0);
- size_t desc_count = buffer_size / m_desc_page_size;
+ uint32_t desc_count = buffer_size / m_desc_page_size;
if (m_mapped_user_buffer) {
LOGGER__ERROR("m_mapped_user_buffer is not NULL");
return HAILO_INVALID_OPERATION;
}
- auto mapped_buffer = VdmaBuffer::create(buffer_size, m_direction, m_driver);
+ auto mapped_buffer = vdma::MappedBuffer::create(buffer_size, m_direction, m_driver);
if(!mapped_buffer) {
LOGGER__ERROR("create mapped buffer failed");
return mapped_buffer.status();
return descriptors.status();
}
- auto status = descriptors->configure_to_use_buffer(mapped_buffer.value(), channel_index);
+ auto status = descriptors->configure_to_use_buffer(mapped_buffer.value(), m_channel_index);
if (status != HAILO_SUCCESS) {
LOGGER__ERROR("connect descriptor list to buffer failed");
return status;
}
- m_mapped_user_buffer = make_unique_nothrow<VdmaBuffer>(mapped_buffer.release());
+ m_mapped_user_buffer = make_unique_nothrow<vdma::MappedBuffer>(mapped_buffer.release());
CHECK_NOT_NULL(m_mapped_user_buffer, HAILO_OUT_OF_HOST_MEMORY);
m_descriptors_buffer = make_unique_nothrow<VdmaDescriptorList>(descriptors.release());
// situation correctly.
assert(m_state);
+ std::lock_guard<State> state_guard(*m_state);
int processed_no = 0;
int head = CB_HEAD(m_state->m_buffers);
auto channel_error = m_host_registers.get_channel_error();
CHECK_EXPECTED_AS_STATUS(channel_error, "Fail to read vdma channel error register");
- CHECK(0 == channel_error.value(), HAILO_INTERNAL_FAILURE, "Vdma channel {} in error state {}", channel_index, channel_error.value());
+ CHECK(0 == channel_error.value(), HAILO_INTERNAL_FAILURE, "Vdma channel {} in error state {}", m_channel_index, channel_error.value());
uint16_t last_num_processed = static_cast<uint16_t>(CB_TAIL(m_state->m_descs));
uint16_t last_desc_index = static_cast<uint16_t>(m_state->m_pending_buffers[tail].last_desc);
// Transfer is complete if its last descriptor is in [last_num_processed, hw_num_processed) or
// the the buffer is empty (hw_num_processed == get_num_available())
- bool is_complete = (is_desc_between(last_num_processed, hw_num_processed, last_desc_index) ||
- hw_num_processed == get_num_available());
+ bool is_complete = is_desc_between(last_num_processed, hw_num_processed, last_desc_index) || (hw_num_processed == get_num_available());
#ifndef NDEBUG
auto status = (*m_descriptors_buffer)[last_desc_index].RemainingPageSize_Status & 0xFF;
// Verify if a DMA Descriptor error occurred.
if (status & 0x2) {
- LOGGER__ERROR("Error while processing descriptor {} of DMA {} on board {}.", last_desc_index, channel_index,
+ LOGGER__ERROR("Error while processing descriptor {} of DMA {} on board {}.", last_desc_index, m_channel_index,
m_driver.dev_path());
return HAILO_INTERNAL_FAILURE;
}
// TODO: use a different macro instead?
_CB_SET(m_state->m_descs.tail, (m_state->m_pending_buffers[last_tail].last_desc + 1) & m_state->m_descs.size_mask);
CB_DEQUEUE(m_state->m_buffers, processed_no);
+
+ if (Direction::H2D == m_direction) {
+ m_can_write_buffer_cv.notify_one();
+ }
}
+ m_is_waiting_for_channel_completion = false;
return HAILO_SUCCESS;
}
hailo_status VdmaChannel::prepare_descriptors(size_t transfer_size, VdmaInterruptsDomain first_desc_interrupts_domain,
VdmaInterruptsDomain last_desc_interrupts_domain)
{
+ MICROPROFILE_SCOPEI("vDMA Channel", "Trigger vDMA", 0);
+
assert(m_descriptors_buffer);
assert(m_state);
auto &desc_info = *m_descriptors_buffer;
auto actual_desc_count = desc_info.program_descriptors(transfer_size, first_desc_interrupts_domain,
last_desc_interrupts_domain, num_available, true);
if (!actual_desc_count) {
- LOGGER__ERROR("Failed to program desc_list for channel {}", channel_index);
+ LOGGER__ERROR("Failed to program desc_list for channel {}", m_channel_index);
return actual_desc_count.status();
}
assert (actual_desc_count.value() == desc_num);
hailo_status VdmaChannel::wait_for_condition(std::function<bool()> condition, std::chrono::milliseconds timeout)
{
- hailo_status status = HAILO_UNINITIALIZED;
auto start_time = std::chrono::steady_clock::now();
std::chrono::milliseconds time_elapsed(0);
while (timeout > time_elapsed) {
return HAILO_SUCCESS;
}
- auto hw_num_processed = wait_interrupts(timeout);
- if ((hw_num_processed.status() == HAILO_TIMEOUT) ||
- (hw_num_processed && hw_num_processed.value() == 0)) {
- // We need to check for channel abort in this 2 cases:
- // 1. TIMEOUT - maybe the timeout is a result of channel aborted.
- // 2. hw_num_processed == 0 - In this case we receive an interrupt, but the channel may be
- // aborted. When the channel is aborted, num processed is set to 0.
- auto is_aborted_exp = is_aborted();
- CHECK_EXPECTED_AS_STATUS(is_aborted_exp);
- if (is_aborted_exp.value()) {
- LOGGER__CRITICAL("Channel {} was aborted by an external source!", channel_index);
- return HAILO_STREAM_ABORTED;
- }
- }
- if ((HAILO_STREAM_INTERNAL_ABORT == hw_num_processed.status()) ||
- (HAILO_STREAM_NOT_ACTIVATED == hw_num_processed.status())) {
- return hw_num_processed.status();
+ auto status = wait_for_channel_completion(timeout);
+ if (HAILO_SUCCESS != status) {
+ return status;
}
- CHECK_EXPECTED_AS_STATUS(hw_num_processed);
-
- status = trigger_channel_completion(hw_num_processed.value());
- CHECK_SUCCESS(status);
time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time);
}
return condition() ? HAILO_SUCCESS : HAILO_TIMEOUT;
}
+hailo_status VdmaChannel::wait_for_channel_completion(std::chrono::milliseconds timeout)
+{
+ auto hw_num_processed = wait_interrupts(timeout);
+ if ((hw_num_processed.status() == HAILO_TIMEOUT) ||
+ (hw_num_processed && hw_num_processed.value() == 0)) {
+ // We need to check for channel abort in this 2 cases:
+ // 1. TIMEOUT - maybe the timeout is a result of channel aborted.
+ // 2. hw_num_processed == 0 - In this case we receive an interrupt, but the channel may be
+ // aborted. When the channel is aborted, num processed is set to 0.
+ auto is_aborted_exp = is_aborted();
+ CHECK_EXPECTED_AS_STATUS(is_aborted_exp);
+ if (is_aborted_exp.value()) {
+ LOGGER__CRITICAL("Channel {} was aborted by an external source!", m_channel_index);
+ return HAILO_STREAM_ABORTED;
+ }
+ }
+ if ((HAILO_STREAM_INTERNAL_ABORT == hw_num_processed.status()) ||
+ (HAILO_STREAM_NOT_ACTIVATED == hw_num_processed.status())) {
+ return hw_num_processed.status();
+ }
+ CHECK_EXPECTED_AS_STATUS(hw_num_processed);
+
+ auto status = trigger_channel_completion(hw_num_processed.value());
+ CHECK_SUCCESS(status);
+
+ return HAILO_SUCCESS;
+}
+
Expected<uint16_t> VdmaChannel::wait_interrupts(std::chrono::milliseconds timeout)
{
assert(m_state);
- auto irq_data = m_driver.wait_channel_interrupts(channel_index, *m_channel_handle, timeout);
+ auto irq_data = m_driver.wait_channel_interrupts(m_channel_index, *m_channel_handle, timeout);
if ((HAILO_STREAM_INTERNAL_ABORT == irq_data.status()) ||
(HAILO_STREAM_NOT_ACTIVATED == irq_data.status())) {
LOGGER__INFO("Wait channel interrupts was aborted!");
#include "vdma_channel_regs.hpp"
#include "hailo/expected.hpp"
#include "os/hailort_driver.hpp"
-#include "vdma_buffer.hpp"
+#include "vdma/mapped_buffer.hpp"
#include "vdma_descriptor_list.hpp"
+#include "hailo/buffer.hpp"
#include <mutex>
#include <array>
+#include <condition_variable>
namespace hailort
{
+class VdmaChannel;
+class PendingBufferState final
+{
+public:
+ PendingBufferState(VdmaChannel &vdma_channel, size_t next_buffer_desc_num) : m_vdma_channel(vdma_channel),
+ m_next_buffer_desc_num(next_buffer_desc_num) {}
+ hailo_status finish(std::chrono::milliseconds timeout, std::unique_lock<std::mutex> &lock);
+
+private:
+ VdmaChannel &m_vdma_channel;
+ size_t m_next_buffer_desc_num;
+};
+
class VdmaChannel final
{
public:
hailo_status wait(size_t buffer_size, const std::chrono::milliseconds &timeout);
hailo_status transfer(void *buf, size_t count);
+ hailo_status write_buffer(const MemoryView &buffer, std::chrono::milliseconds timeout);
+ Expected<PendingBufferState> send_pending_buffer();
hailo_status trigger_channel_completion(uint16_t hw_num_processed);
hailo_status allocate_resources(uint32_t descs_count);
/* For channels controlled by the HailoRT, the HailoRT needs to use this function to start the channel (it registers the channel to driver
hailo_status unregister_fw_controlled_channel();
hailo_status flush(const std::chrono::milliseconds &timeout);
hailo_status set_num_avail_value(uint16_t new_value);
+ hailo_status set_transfers_per_axi_intr(uint16_t transfers_per_axi_intr);
hailo_status inc_num_available_for_ddr(uint16_t value, uint32_t size_mask);
- hailo_status wait_channel_interrupts_for_ddr(const std::chrono::milliseconds &timeout);
Expected<uint16_t> get_hw_num_processed_ddr(uint32_t size_mask);
/*Used for DDR channels only. TODO - remove */
hailo_status start_channel(VdmaDescriptorList &desc_list);
hailo_status abort();
hailo_status clear_abort();
+ uint8_t get_channel_index()
+ {
+ return m_channel_index;
+ }
+
VdmaChannel(const VdmaChannel &other) = delete;
VdmaChannel &operator=(const VdmaChannel &other) = delete;
VdmaChannel(VdmaChannel &&other) noexcept;
uint16_t requested_desc_page_size);
- const uint8_t channel_index;
+ const uint8_t m_channel_index;
+
+ friend class PendingBufferState;
private:
struct PendingBuffer {
VdmaChannel(uint8_t channel_index, Direction direction, HailoRTDriver &driver, uint32_t stream_index,
LatencyMeterPtr latency_meter, uint16_t desc_page_size, uint16_t transfers_per_axi_intr, hailo_status &status);
- hailo_status allocate_buffer(const size_t buffer_size);
+ hailo_status allocate_buffer(const uint32_t buffer_size);
void clear_descriptor_list();
hailo_status release_buffer();
static Direction other_direction(const Direction direction);
hailo_status transfer_h2d(void *buf, size_t count);
+ hailo_status write_buffer_impl(const MemoryView &buffer);
+ hailo_status send_pending_buffer_impl();
uint16_t get_num_available();
Expected<uint16_t> get_hw_num_processed();
void add_pending_buffer(uint32_t first_desc, uint32_t last_desc);
VdmaInterruptsDomain last_desc_interrupts_domain);
hailo_status prepare_d2h_pending_descriptors(uint32_t descs_count, uint32_t transfer_size);
void reset_internal_counters();
+ hailo_status wait_for_channel_completion(std::chrono::milliseconds timeout);
uint32_t calculate_descriptors_count(uint32_t buffer_size);
// TODO: remove the unique_ptr, instead allocate the buffer in the ctor (needs to move ddr channel to
// other class)
- std::unique_ptr<VdmaBuffer> m_mapped_user_buffer;
+ std::unique_ptr<vdma::MappedBuffer> m_mapped_user_buffer;
std::unique_ptr<VdmaDescriptorList> m_descriptors_buffer;
uint32_t m_stream_index;
LatencyMeterPtr m_latency_meter;
bool m_channel_enabled;
uint16_t m_transfers_per_axi_intr;
+ // Using CircularArray because it won't allocate or free memory wile pushing and poping. The fact that it is circural is not relevant here
+ CircularArray<size_t> m_pending_buffers_sizes;
+ uint16_t m_pending_num_avail_offset;
+ std::condition_variable_any m_can_write_buffer_cv;
+ std::atomic_bool m_is_waiting_for_channel_completion;
+ bool m_is_aborted;
};
} /* namespace hailort */
#define DESC_PAGE_SIZE_SHIFT (8)
#define DESC_PAGE_SIZE_MASK (0xFFFFFF00)
+#define DESC_IRQ_MASK (0x0000003C)
namespace hailort
{
-Expected<VdmaDescriptorList> VdmaDescriptorList::create(size_t desc_count, uint16_t requested_desc_page_size,
+Expected<VdmaDescriptorList> VdmaDescriptorList::create(uint32_t desc_count, uint16_t requested_desc_page_size,
HailoRTDriver &driver)
{
hailo_status status = HAILO_UNINITIALIZED;
return object;
}
-VdmaDescriptorList::VdmaDescriptorList(size_t desc_count, HailoRTDriver &driver, uint16_t desc_page_size,
+VdmaDescriptorList::VdmaDescriptorList(uint32_t desc_count, HailoRTDriver &driver, uint16_t desc_page_size,
hailo_status &status) :
m_mapped_list(),
m_count(desc_count),
return static_cast<uint8_t>(depth);
}
-hailo_status VdmaDescriptorList::configure_to_use_buffer(VdmaBuffer& buffer, uint8_t channel_index)
+hailo_status VdmaDescriptorList::configure_to_use_buffer(vdma::MappedBuffer& buffer, uint8_t channel_index)
{
return m_driver.descriptors_list_bind_vdma_buffer(m_desc_handle, buffer.handle(), m_desc_page_size,
channel_index);
}
-hailo_status VdmaDescriptorList::configure_to_use_buffer(VdmaBuffer& buffer)
+hailo_status VdmaDescriptorList::configure_to_use_buffer(vdma::MappedBuffer& buffer)
{
return configure_to_use_buffer(buffer, HailoRTDriver::INVALID_VDMA_CHANNEL_INDEX);
}
const auto required_descriptors = descriptors_in_buffer(transfer_size);
// Required_descriptors + desc_offset can't reach m_count. We need to keep at least 1 free desc at all time.
if ((!is_circular) && ((required_descriptors + desc_offset) >= m_count)){
- LOGGER__ERROR("Requested transfer size ({}) result in more descrptors than available ({})", transfer_size, m_count);
+ LOGGER__ERROR("Requested transfer size ({}) result in more descriptors than available ({})", transfer_size, m_count);
return make_unexpected(HAILO_OUT_OF_DESCRIPTORS);
}
return std::move(static_cast<uint16_t>(required_descriptors));
}
-Expected<uint16_t> VdmaDescriptorList::program_descs_for_ddr_transfers(uint32_t row_size, bool should_raise_interrupt,
- uint32_t number_of_rows_per_intrpt, uint32_t buffered_rows, uint16_t initial_descs_offset, bool is_circular)
+hailo_status VdmaDescriptorList::reprogram_descriptor_interrupts_domain(size_t desc_index,
+ VdmaInterruptsDomain interrupts_domain)
{
- uint16_t programmed_descs = 0;
- size_t offset = initial_descs_offset;
- assert(0 == (buffered_rows % number_of_rows_per_intrpt));
-
- auto first_desc_interrupts_mask = VdmaInterruptsDomain::NONE;
- auto last_desc_interrupts_mask = (should_raise_interrupt) ? VdmaInterruptsDomain::HOST : VdmaInterruptsDomain::NONE;
- for (uint32_t rows_count = 0; rows_count < buffered_rows; rows_count += number_of_rows_per_intrpt) {
- auto desc_count_local = program_descriptors((row_size * number_of_rows_per_intrpt),
- first_desc_interrupts_mask, last_desc_interrupts_mask, offset, is_circular);
- CHECK_EXPECTED(desc_count_local);
- offset = (offset + desc_count_local.value()) & (m_count - 1);
- programmed_descs = static_cast<uint16_t>(programmed_descs + desc_count_local.value());
+ if (desc_index >= m_count){
+ LOGGER__ERROR("Requested desc (index={}) exceeds the number of descriptors in the list ({})", desc_index, m_count);
+ return HAILO_OUT_OF_DESCRIPTORS;
}
- return programmed_descs;
+ reprogram_single_descriptor_interrupts_domain((*this)[desc_index], interrupts_domain);
+ return HAILO_SUCCESS;
}
uint32_t VdmaDescriptorList::descriptors_in_buffer(size_t buffer_size) const
uint32_t VdmaDescriptorList::descriptors_in_buffer(size_t buffer_size, uint16_t desc_page_size)
{
assert(buffer_size < std::numeric_limits<uint32_t>::max());
- return static_cast<uint32_t>(((buffer_size) + desc_page_size - 1) / desc_page_size);
+ return static_cast<uint32_t>(DESCRIPTORS_IN_BUFFER(buffer_size, desc_page_size));
}
uint32_t VdmaDescriptorList::calculate_descriptors_count(uint32_t buffer_size, uint16_t batch_size, uint16_t desc_page_size)
CHECK_AS_EXPECTED(local_desc_page_size <= max_desc_page_size, HAILO_OUT_OF_DESCRIPTORS,
"Network shapes and batch size exceeds driver descriptors capabilities. "
- "Required descriptors count: {}, max allowed on the driver: {}.",
- (batch_size * acc_desc_count), MAX_DESCS_COUNT);
+ "Required descriptors count: {}, max allowed on the driver: {}. (A common cause for this error could be the"
+ "Batch size - which is {}).",
+ (batch_size * acc_desc_count), MAX_DESCS_COUNT, batch_size);
CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(local_desc_page_size), HAILO_INTERNAL_FAILURE,
"Descriptor page size needs to fit in 16B");
(uint32_t)(page_size << DESC_PAGE_SIZE_SHIFT) & (uint32_t)DESC_PAGE_SIZE_MASK;
if (VdmaInterruptsDomain::NONE != interrupts_domain) {
- // update the desc_control
- descriptor.PageSize_DescControl |= (DESC_REQUREST_IRQ_PROCESSED | DESC_REQUREST_IRQ_ERR);
+ // Update the desc_control
+ descriptor.PageSize_DescControl |= (DESC_REQUREST_IRQ_PROCESSED | DESC_REQUREST_IRQ_ERR |
+ get_interrupts_bitmask(interrupts_domain));
#ifndef NDEBUG
descriptor.PageSize_DescControl |= (DESC_STATUS_REQ | DESC_STATUS_REQ_ERR);
#endif
- descriptor.PageSize_DescControl |= get_interrupts_bitmask(interrupts_domain);
}
// Clear status
descriptor.RemainingPageSize_Status = 0;
}
+void VdmaDescriptorList::reprogram_single_descriptor_interrupts_domain(VdmaDescriptor &descriptor,
+ VdmaInterruptsDomain interrupts_domain)
+{
+ // Set the IRQ control bits to zero
+ descriptor.PageSize_DescControl &= ~DESC_IRQ_MASK;
+
+ if (VdmaInterruptsDomain::NONE == interrupts_domain) {
+ // Nothing else to do
+ return;
+ }
+
+ descriptor.PageSize_DescControl |= (DESC_REQUREST_IRQ_PROCESSED | DESC_REQUREST_IRQ_ERR |
+ get_interrupts_bitmask(interrupts_domain));
+}
+
} /* namespace hailort */
#include "os/hailort_driver.hpp"
#include "hailo/expected.hpp"
#include "os/mmap_buffer.hpp"
-#include "vdma_buffer.hpp"
+#include "vdma/mapped_buffer.hpp"
#include "common/utils.hpp"
namespace hailort
class VdmaDescriptorList
{
public:
- static Expected<VdmaDescriptorList> create(size_t desc_count, uint16_t requested_desc_page_size,
+ static Expected<VdmaDescriptorList> create(uint32_t desc_count, uint16_t requested_desc_page_size,
HailoRTDriver &driver);
~VdmaDescriptorList();
return m_depth;
}
- size_t count() const
+ uint32_t count() const
{
return m_count;
}
return m_desc_handle;
}
- hailo_status configure_to_use_buffer(VdmaBuffer& buffer, uint8_t channel_index);
+ hailo_status configure_to_use_buffer(vdma::MappedBuffer& buffer, uint8_t channel_index);
// On hailo8, we allow configuring buffer without specific channel index.
- hailo_status configure_to_use_buffer(VdmaBuffer& buffer);
+ hailo_status configure_to_use_buffer(vdma::MappedBuffer& buffer);
Expected<uint16_t> program_descriptors(size_t transfer_size, VdmaInterruptsDomain first_desc_interrupts_domain,
VdmaInterruptsDomain last_desc_interrupts_domain, size_t desc_offset, bool is_circular);
-
- Expected<uint16_t> program_descs_for_ddr_transfers(uint32_t row_size, bool should_raise_interrupt,
- uint32_t number_of_rows_per_intrpt, uint32_t buffered_rows, uint16_t initial_descs_offset, bool is_circular);
+ hailo_status reprogram_descriptor_interrupts_domain(size_t desc_index, VdmaInterruptsDomain interrupts_domain);
uint32_t descriptors_in_buffer(size_t buffer_size) const;
static uint32_t descriptors_in_buffer(size_t buffer_size, uint16_t desc_page_size);
uint16_t batch_size, const std::vector<uint32_t> &transfer_sizes);
private:
- VdmaDescriptorList(size_t desc_count, HailoRTDriver &driver, uint16_t desc_page_size, hailo_status &status);
+ VdmaDescriptorList(uint32_t desc_count, HailoRTDriver &driver, uint16_t desc_page_size, hailo_status &status);
uint32_t get_interrupts_bitmask(VdmaInterruptsDomain interrupts_domain);
void program_single_descriptor(VdmaDescriptor &descriptor, uint16_t page_size,
VdmaInterruptsDomain interrupts_domain);
+ void reprogram_single_descriptor_interrupts_domain(VdmaDescriptor &descriptor, VdmaInterruptsDomain interrupts_domain);
static Expected<uint8_t> calculate_desc_list_depth(size_t count);
// Note: initial_desc_page_size should be the optimal descriptor page size.
static Expected<std::pair<uint16_t, uint32_t>> get_desc_buffer_sizes_for_single_transfer_impl(
uint16_t initial_desc_page_size);
MmapBuffer<VdmaDescriptor> m_mapped_list;
- size_t m_count;
+ uint32_t m_count;
uint8_t m_depth;
uintptr_t m_desc_handle;
uint64_t m_dma_address;
namespace hailort
{
-VdmaInputStream::VdmaInputStream(VdmaDevice &device, uint8_t channel_index, const LayerInfo &edge_layer,
- EventPtr network_group_activated_event, uint16_t batch_size,
- LatencyMeterPtr latency_meter, std::chrono::milliseconds transfer_timeout,
+VdmaInputStream::VdmaInputStream(VdmaDevice &device, std::shared_ptr<VdmaChannel> channel,
+ const LayerInfo &edge_layer, EventPtr network_group_activated_event, uint16_t batch_size,
+ std::chrono::milliseconds transfer_timeout,
hailo_stream_interface_t stream_interface, hailo_status &status) :
InputStreamBase(edge_layer, stream_interface, std::move(network_group_activated_event), status),
m_device(&device),
- m_channel_index(channel_index),
+ m_channel(std::move(channel)),
is_stream_activated(false),
m_channel_timeout(transfer_timeout),
- m_latency_meter(latency_meter),
- m_batch_size(batch_size)
+ m_max_batch_size(batch_size),
+ m_dynamic_batch_size(batch_size)
{
// Checking status for base class c'tor
if (HAILO_SUCCESS != status) {
return;
}
- status = config_stream();
- if (HAILO_SUCCESS != status) {
- return;
- }
-
status = HAILO_SUCCESS;
}
VdmaInputStream::VdmaInputStream(VdmaInputStream &&other) :
InputStreamBase(std::move(other)),
m_device(std::move(other.m_device)),
- m_channel_index(std::move(other.m_channel_index)),
m_channel(std::move(other.m_channel)),
is_stream_activated(std::exchange(other.is_stream_activated, false)),
m_channel_timeout(std::move(other.m_channel_timeout)),
- m_latency_meter(std::move(other.m_latency_meter)),
- m_batch_size(other.m_batch_size)
+ m_max_batch_size(other.m_max_batch_size),
+ m_dynamic_batch_size(other.m_dynamic_batch_size)
{}
std::chrono::milliseconds VdmaInputStream::get_timeout() const
hailo_status VdmaInputStream::flush()
{
- return m_channel->flush((m_channel_timeout * m_batch_size));
+ return m_channel->flush((m_channel_timeout * m_dynamic_batch_size));
}
-hailo_status VdmaInputStream::activate_stream()
+hailo_status VdmaInputStream::activate_stream(uint16_t dynamic_batch_size)
{
- auto status = m_channel->start_allocated_channel(0);
+ auto status = set_dynamic_batch_size(dynamic_batch_size);
+ CHECK_SUCCESS(status);
+
+ status = m_channel->start_allocated_channel(0);
CHECK_SUCCESS(status);
this->is_stream_activated = true;
/* Flush is best effort */
auto status = m_channel->flush(VDMA_FLUSH_TIMEOUT);
if (HAILO_STREAM_INTERNAL_ABORT == status) {
- LOGGER__INFO("Flush input_channel is not needed because channel was aborted. (channel {})", m_channel_index);
+ LOGGER__INFO("Flush input_channel is not needed because channel was aborted. (channel {})", m_channel->get_channel_index());
status = HAILO_SUCCESS;
} else if (HAILO_SUCCESS != status) {
- LOGGER__ERROR("Failed to flush input_channel. (status {} channel {})", status, m_channel_index);
+ LOGGER__ERROR("Failed to flush input_channel. (status {} channel {})", status, m_channel->get_channel_index());
}
/* Close channel is best effort. */
return buffer.size();
}
-hailo_status VdmaInputStream::sync_write_all_raw_buffer_no_transform_impl(void *buffer, size_t offset, size_t size)
+hailo_status VdmaInputStream::write_buffer_only(const MemoryView &buffer)
{
- ASSERT(NULL != buffer);
-
- return sync_write_raw_buffer(MemoryView(static_cast<uint8_t*>(buffer) + offset, size)).status();
+ return m_channel->write_buffer(buffer, m_channel_timeout);
}
-hailo_status VdmaInputStream::config_stream()
+Expected<PendingBufferState> VdmaInputStream::send_pending_buffer()
{
- hailo_status status = HAILO_UNINITIALIZED;
- uint32_t descs_count = 0;
- uint16_t page_size = 0;
- uint32_t min_active_trans = MIN_ACTIVE_TRANSFERS_SCALE * m_batch_size;
- uint32_t max_active_trans = MAX_ACTIVE_TRANSFERS_SCALE * m_batch_size;
- assert(min_active_trans <= max_active_trans);
-
- CHECK(IS_FIT_IN_UINT16(min_active_trans), HAILO_INVALID_ARGUMENT,
- "calculated min_active_trans for vdma descriptor list is out of UINT16 range");
+ hailo_status status = m_channel->wait(get_frame_size(), m_channel_timeout);
+ if ((HAILO_STREAM_INTERNAL_ABORT == status) || (HAILO_STREAM_NOT_ACTIVATED == status)) {
+ return make_unexpected(status);
+ }
+ CHECK_SUCCESS_AS_EXPECTED(status);
- CHECK(IS_FIT_IN_UINT16(max_active_trans), HAILO_INVALID_ARGUMENT,
- "calculated min_active_trans for vdma descriptor list is out of UINT16 range");
+ return m_channel->send_pending_buffer();
+}
- auto desc_sizes_pair = VdmaDescriptorList::get_desc_buffer_sizes_for_single_transfer(m_device->get_driver(),
- static_cast<uint16_t>(min_active_trans), static_cast<uint16_t>(max_active_trans), m_stream_info.hw_frame_size);
- CHECK_EXPECTED_AS_STATUS(desc_sizes_pair);
+uint16_t VdmaInputStream::get_dynamic_batch_size() const
+{
+ return m_dynamic_batch_size;
+}
- page_size = desc_sizes_pair->first;
- descs_count = desc_sizes_pair->second;
+const char* VdmaInputStream::get_dev_id() const
+{
+ return m_device->get_dev_id();
+}
- auto channel = VdmaChannel::create(m_channel_index, VdmaChannel::Direction::H2D, m_device->get_driver(), page_size,
- m_stream_info.index, m_latency_meter, m_batch_size);
+hailo_status VdmaInputStream::sync_write_all_raw_buffer_no_transform_impl(void *buffer, size_t offset, size_t size)
+{
+ ASSERT(NULL != buffer);
- m_channel = make_unique_nothrow<VdmaChannel>(channel.release());
- CHECK(nullptr != m_channel, HAILO_OUT_OF_HOST_MEMORY);
+ return sync_write_raw_buffer(MemoryView(static_cast<uint8_t*>(buffer) + offset, size)).status();
+}
- status = m_channel->allocate_resources(descs_count);
- CHECK_SUCCESS(status);
+hailo_status VdmaInputStream::set_dynamic_batch_size(uint16_t dynamic_batch_size)
+{
+ CHECK(dynamic_batch_size <= m_max_batch_size, HAILO_INVALID_ARGUMENT,
+ "Dynamic batch size ({}) must be <= than the configured batch size ({})",
+ dynamic_batch_size, m_max_batch_size);
+
+ if (CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE == dynamic_batch_size) {
+ LOGGER__TRACE("Received CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE == dynamic_batch_size; "
+ "Leaving previously set value of {}", m_dynamic_batch_size);
+ } else {
+ LOGGER__TRACE("Setting stream's dynamic_batch_size to {}", dynamic_batch_size);
+ m_dynamic_batch_size = dynamic_batch_size;
+
+ const auto status = m_channel->set_transfers_per_axi_intr(m_dynamic_batch_size);
+ CHECK_SUCCESS(status);
+ }
return HAILO_SUCCESS;
}
/** Output stream **/
-VdmaOutputStream::VdmaOutputStream(VdmaDevice &device, uint8_t channel_index, const LayerInfo &edge_layer,
- EventPtr network_group_activated_event, uint16_t batch_size,
- LatencyMeterPtr latency_meter, std::chrono::milliseconds transfer_timeout,
- hailo_status &status) :
+VdmaOutputStream::VdmaOutputStream(VdmaDevice &device, std::shared_ptr<VdmaChannel> channel,
+ const LayerInfo &edge_layer, EventPtr network_group_activated_event, uint16_t batch_size,
+ std::chrono::milliseconds transfer_timeout, hailo_status &status) :
OutputStreamBase(edge_layer, std::move(network_group_activated_event), status),
m_device(&device),
- m_channel_index(channel_index),
+ m_channel(std::move(channel)),
is_stream_activated(false),
m_transfer_timeout(transfer_timeout),
- m_latency_meter(latency_meter),
- m_batch_size(batch_size),
+ m_max_batch_size(batch_size),
+ m_dynamic_batch_size(batch_size),
m_transfer_size(get_transfer_size(m_stream_info))
{
// Check status for base class c'tor
return;
}
- status = config_stream();
- if (HAILO_SUCCESS != status) {
- return;
- }
-
status = HAILO_SUCCESS;
}
VdmaOutputStream::VdmaOutputStream(VdmaOutputStream &&other) :
OutputStreamBase(std::move(other)),
m_device(std::move(other.m_device)),
- m_channel_index(std::move(other.m_channel_index)),
m_channel(std::move(other.m_channel)),
is_stream_activated(std::exchange(other.is_stream_activated, false)),
m_transfer_timeout(std::move(other.m_transfer_timeout)),
- m_latency_meter(std::move(other.m_latency_meter)),
- m_batch_size(other.m_batch_size),
+ m_max_batch_size(other.m_max_batch_size),
+ m_dynamic_batch_size(other.m_dynamic_batch_size),
m_transfer_size(other.m_transfer_size)
{}
return m_channel->clear_abort();
}
-hailo_status VdmaOutputStream::activate_stream()
+uint16_t VdmaOutputStream::get_dynamic_batch_size() const
+{
+ return m_dynamic_batch_size;
+}
+
+const char* VdmaOutputStream::get_dev_id() const
{
- auto status = m_channel->start_allocated_channel(m_transfer_size);
+ return m_device->get_dev_id();
+}
+
+hailo_status VdmaOutputStream::activate_stream(uint16_t dynamic_batch_size)
+{
+ auto status = set_dynamic_batch_size(dynamic_batch_size);
+ CHECK_SUCCESS(status);
+
+ status = m_channel->start_allocated_channel(m_transfer_size);
CHECK_SUCCESS(status);
this->is_stream_activated = true;
return buffer.size();
}
-hailo_status VdmaOutputStream::config_stream()
-{
- const uint32_t min_active_trans = MIN_ACTIVE_TRANSFERS_SCALE * m_batch_size;
- const uint32_t max_active_trans = MAX_ACTIVE_TRANSFERS_SCALE * m_batch_size;
- assert(min_active_trans <= max_active_trans);
-
- CHECK(IS_FIT_IN_UINT16(min_active_trans), HAILO_INVALID_ARGUMENT,
- "calculated min_active_trans for vdma descriptor list is out of UINT16 range");
-
- CHECK(IS_FIT_IN_UINT16(max_active_trans), HAILO_INVALID_ARGUMENT,
- "calculated min_active_trans for vdma descriptor list is out of UINT16 range");
-
- auto desc_sizes_pair = VdmaDescriptorList::get_desc_buffer_sizes_for_single_transfer(m_device->get_driver(),
- static_cast<uint16_t>(min_active_trans), static_cast<uint16_t>(max_active_trans), m_transfer_size);
- CHECK_EXPECTED_AS_STATUS(desc_sizes_pair);
-
- const auto page_size = desc_sizes_pair->first;
- auto channel = VdmaChannel::create(m_channel_index, VdmaChannel::Direction::D2H, m_device->get_driver(), page_size,
- m_stream_info.index, m_latency_meter, m_batch_size);
-
- m_channel = make_unique_nothrow<VdmaChannel>(channel.release());
- CHECK(nullptr != m_channel, HAILO_OUT_OF_HOST_MEMORY);
-
- const auto descs_count = desc_sizes_pair->second;
- const auto status = m_channel->allocate_resources(descs_count);
- CHECK_SUCCESS(status);
-
- return HAILO_SUCCESS;
-}
-
hailo_status VdmaOutputStream::read_all(MemoryView &buffer)
{
CHECK((buffer.size() % HailoRTCommon::HW_DATA_ALIGNMENT) == 0, HAILO_INVALID_ARGUMENT,
stream_info.nms_info.bbox_size : stream_info.hw_frame_size;
}
+hailo_status VdmaOutputStream::set_dynamic_batch_size(uint16_t dynamic_batch_size)
+{
+ CHECK(dynamic_batch_size <= m_max_batch_size, HAILO_INVALID_ARGUMENT,
+ "Dynamic batch size ({}) must be <= than the configured batch size ({})",
+ dynamic_batch_size, m_max_batch_size);
+
+ if (CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE == dynamic_batch_size) {
+ LOGGER__TRACE("Received CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE == dynamic_batch_size; "
+ "Leaving previously set value of {}", m_dynamic_batch_size);
+ } else {
+ LOGGER__TRACE("Setting stream's dynamic_batch_size to {}", dynamic_batch_size);
+ m_dynamic_batch_size = dynamic_batch_size;
+
+ const auto status = m_channel->set_transfers_per_axi_intr(m_dynamic_batch_size);
+ CHECK_SUCCESS(status);
+ }
+
+ return HAILO_SUCCESS;
+}
+
} /* namespace hailort */
virtual hailo_status abort() override;
virtual hailo_status clear_abort() override;
virtual hailo_status flush() override;
-
- uint16_t get_batch_size() const
- {
- return m_batch_size;
- }
-
- const char* get_dev_id() const
- {
- return m_device->get_dev_id();
- }
+ hailo_status write_buffer_only(const MemoryView &buffer);
+ Expected<PendingBufferState> send_pending_buffer();
+ uint16_t get_dynamic_batch_size() const;
+ const char* get_dev_id() const;
protected:
- VdmaInputStream(VdmaDevice &device, uint8_t channel_index, const LayerInfo &edge_layer,
- EventPtr network_group_activated_event, uint16_t batch_size, LatencyMeterPtr latency_meter,
+ VdmaInputStream(VdmaDevice &device, std::shared_ptr<VdmaChannel> channel, const LayerInfo &edge_layer,
+ EventPtr network_group_activated_event, uint16_t batch_size,
std::chrono::milliseconds transfer_timeout, hailo_stream_interface_t stream_interface,
hailo_status &status);
- virtual hailo_status activate_stream() override;
+ virtual hailo_status activate_stream(uint16_t dynamic_batch_size) override;
virtual hailo_status deactivate_stream() override;
virtual Expected<size_t> sync_write_raw_buffer(const MemoryView &buffer) override;
virtual hailo_status sync_write_all_raw_buffer_no_transform_impl(void *buffer, size_t offset, size_t size) override;
VdmaDevice *m_device;
- const uint8_t m_channel_index;
- std::unique_ptr<VdmaChannel> m_channel;
+ std::shared_ptr<VdmaChannel> m_channel;
private:
- hailo_status config_stream();
+ hailo_status set_dynamic_batch_size(uint16_t dynamic_batch_size);
bool is_stream_activated;
std::chrono::milliseconds m_channel_timeout;
- LatencyMeterPtr m_latency_meter;
- uint16_t m_batch_size;
+ const uint16_t m_max_batch_size;
+ uint16_t m_dynamic_batch_size;
};
class VdmaOutputStream : public OutputStreamBase {
virtual hailo_status set_timeout(std::chrono::milliseconds timeout) override;
virtual hailo_status abort() override;
virtual hailo_status clear_abort() override;
-
- uint16_t get_batch_size() const
- {
- return m_batch_size;
- }
-
- const char* get_dev_id() const
- {
- return m_device->get_dev_id();
- }
+ uint16_t get_dynamic_batch_size() const;
+ const char* get_dev_id() const;
protected:
- VdmaOutputStream(VdmaDevice &device, uint8_t channel_index, const LayerInfo &edge_layer,
- EventPtr network_group_activated_event, uint16_t batch_size, LatencyMeterPtr latency_meter,
+ VdmaOutputStream(VdmaDevice &device, std::shared_ptr<VdmaChannel> channel, const LayerInfo &edge_layer,
+ EventPtr network_group_activated_event, uint16_t batch_size,
std::chrono::milliseconds transfer_timeout, hailo_status &status);
- virtual hailo_status activate_stream() override;
+ virtual hailo_status activate_stream(uint16_t dynamic_batch_size) override;
virtual hailo_status deactivate_stream() override;
virtual Expected<size_t> sync_read_raw_buffer(MemoryView &buffer);
VdmaDevice *m_device;
- const uint8_t m_channel_index;
- std::unique_ptr<VdmaChannel> m_channel;
+ std::shared_ptr<VdmaChannel> m_channel;
private:
- hailo_status config_stream();
hailo_status read_all(MemoryView &buffer) override;
static uint32_t get_transfer_size(const hailo_stream_info_t &stream_info);
+ hailo_status set_dynamic_batch_size(uint16_t dynamic_batch_size);
bool is_stream_activated;
std::chrono::milliseconds m_transfer_timeout;
- LatencyMeterPtr m_latency_meter;
- uint16_t m_batch_size;
+ const uint16_t m_max_batch_size;
+ uint16_t m_dynamic_batch_size;
const uint32_t m_transfer_size;
};
BaseVStream::BaseVStream(const hailo_vstream_info_t &vstream_info, const hailo_vstream_params_t &vstream_params,
std::shared_ptr<PipelineElement> pipeline_entry, std::vector<std::shared_ptr<PipelineElement>> &&pipeline,
- std::shared_ptr<std::atomic<hailo_status>> &&pipeline_status, EventPtr shutdown_event,
- AccumulatorPtr pipeline_latency_accumulator, EventPtr &&network_group_activated_event, hailo_status &output_status) :
+ std::shared_ptr<std::atomic<hailo_status>> &&pipeline_status,
+ EventPtr shutdown_event, AccumulatorPtr pipeline_latency_accumulator, EventPtr &&network_group_activated_event,
+ hailo_status &output_status) :
m_vstream_info(vstream_info),
m_vstream_params(vstream_params),
m_measure_pipeline_latency((vstream_params.vstream_stats_flags & HAILO_VSTREAM_STATS_MEASURE_LATENCY) != 0),
hailo_status BaseVStream::stop_and_clear()
{
- auto status = m_network_group_activated_event->wait(std::chrono::milliseconds(0));
- CHECK(HAILO_TIMEOUT == status, HAILO_INVALID_OPERATION,
+ auto status = m_network_group_activated_event->wait(std::chrono::milliseconds(0));
+ CHECK(HAILO_TIMEOUT == status, HAILO_INVALID_OPERATION,
"Trying to clear {} vstream before its network group is deactivated", name());
-
- status = stop_vstream();
- CHECK_SUCCESS(status);
-
+
+ status = stop_vstream();
+ CHECK_SUCCESS(status);
+
status = m_entry_element->clear();
CHECK_SUCCESS(status, "Failed clearing vstream {}", name());
std::shared_ptr<std::atomic<hailo_status>> &&pipeline_status, EventPtr shutdown_event,
AccumulatorPtr pipeline_latency_accumulator,
EventPtr network_group_activated_event, hailo_status &output_status) :
- BaseVStream(vstream_info, vstream_params, pipeline_entry, std::move(pipeline), std::move(pipeline_status), shutdown_event,
- pipeline_latency_accumulator, std::move(network_group_activated_event), output_status)
+ BaseVStream(vstream_info, vstream_params, pipeline_entry, std::move(pipeline), std::move(pipeline_status),
+ shutdown_event, pipeline_latency_accumulator, std::move(network_group_activated_event), output_status)
{
if (HAILO_SUCCESS != output_status) {
return;
hailo_status InputVStream::write(const MemoryView &buffer)
{
- CHECK(m_is_activated, HAILO_VSTREAM_PIPELINE_NOT_ACTIVATED, "Failed to write buffer! Virtual stream {} is not activated!", name());
- auto status = m_network_group_activated_event->wait(std::chrono::milliseconds(0));
- CHECK(HAILO_TIMEOUT != status, HAILO_NETWORK_GROUP_NOT_ACTIVATED,
- "Trying to write to vstream {} before its network group is activated", name());
- status = m_entry_element->run_push(PipelineBuffer(buffer, m_measure_pipeline_latency));
+ if (nullptr != m_network_group_activated_event) {
+ CHECK(m_is_activated, HAILO_VSTREAM_PIPELINE_NOT_ACTIVATED, "Failed to write buffer! Virtual stream {} is not activated!", name());
+ auto status = m_network_group_activated_event->wait(std::chrono::milliseconds(0));
+ CHECK(HAILO_TIMEOUT != status, HAILO_NETWORK_GROUP_NOT_ACTIVATED,
+ "Trying to write to vstream {} before its network group is activated", name());
+ }
+
+ auto status = m_entry_element->run_push(PipelineBuffer(buffer, m_measure_pipeline_latency));
if (HAILO_SHUTDOWN_EVENT_SIGNALED == status) {
LOGGER__INFO("Sending to VStream was shutdown!");
status = m_pipeline_status->load();
std::shared_ptr<PipelineElement> pipeline_entry, std::vector<std::shared_ptr<PipelineElement>> &&pipeline,
std::shared_ptr<std::atomic<hailo_status>> &&pipeline_status, EventPtr shutdown_event,
EventPtr network_group_activated_event, AccumulatorPtr pipeline_latency_accumulator)
-
{
hailo_status status = HAILO_UNINITIALIZED;
std::shared_ptr<std::atomic<hailo_status>> &&pipeline_status, EventPtr shutdown_event,
AccumulatorPtr pipeline_latency_accumulator,
EventPtr network_group_activated_event, hailo_status &output_status) :
- BaseVStream(vstream_info, vstream_params, pipeline_entry, std::move(pipeline), std::move(pipeline_status), shutdown_event,
- pipeline_latency_accumulator, std::move(network_group_activated_event), output_status)
+ BaseVStream(vstream_info, vstream_params, pipeline_entry, std::move(pipeline), std::move(pipeline_status),
+ shutdown_event, pipeline_latency_accumulator, std::move(network_group_activated_event), output_status)
{
if (HAILO_SUCCESS != output_status) {
return;
hailo_status OutputVStream::read(MemoryView buffer)
{
- CHECK(m_is_activated, HAILO_VSTREAM_PIPELINE_NOT_ACTIVATED, "read() failed! Virtual stream {} is not activated!", name());
- auto status = m_network_group_activated_event->wait(std::chrono::milliseconds(0));
- if (HAILO_TIMEOUT == status) {
- LOGGER__INFO("Trying to read from vstream {} before its network_group is activated", name());
- return HAILO_NETWORK_GROUP_NOT_ACTIVATED;
+ if (nullptr != m_network_group_activated_event) {
+ CHECK(m_is_activated, HAILO_VSTREAM_PIPELINE_NOT_ACTIVATED, "read() failed! Virtual stream {} is not activated!", name());
+ auto status = m_network_group_activated_event->wait(std::chrono::milliseconds(0));
+ if (HAILO_TIMEOUT == status) {
+ LOGGER__INFO("Trying to read from vstream {} before its network_group is activated", name());
+ return HAILO_NETWORK_GROUP_NOT_ACTIVATED;
+ }
+ CHECK_SUCCESS(status);
}
- CHECK_SUCCESS(status);
assert(1 == m_entry_element->sources().size());
auto recv_buffer = m_entry_element->sources()[0].run_pull(PipelineBuffer(buffer, m_measure_pipeline_latency));
- status = recv_buffer.status();
+ auto status = recv_buffer.status();
if (HAILO_SHUTDOWN_EVENT_SIGNALED == status) {
LOGGER__INFO("Receiving to VStream was shutdown!");
status = m_pipeline_status->load();
CHECK_EXPECTED(buffer);
while (true) {
- auto status = m_activation_wait_or_shutdown.wait(m_timeout);
- if (HAILO_SHUTDOWN_EVENT_SIGNALED == status) {
- return make_unexpected(HAILO_SHUTDOWN_EVENT_SIGNALED);
- }
- if (HAILO_TIMEOUT == status) {
- return make_unexpected(HAILO_NETWORK_GROUP_NOT_ACTIVATED);
+ if (!m_stream.is_scheduled()) {
+ auto status = m_activation_wait_or_shutdown.wait(m_timeout);
+ if (HAILO_SHUTDOWN_EVENT_SIGNALED == status) {
+ return make_unexpected(HAILO_SHUTDOWN_EVENT_SIGNALED);
+ }
+ if (HAILO_TIMEOUT == status) {
+ return make_unexpected(HAILO_NETWORK_GROUP_NOT_ACTIVATED);
+ }
+ CHECK_SUCCESS_AS_EXPECTED(status);
+ } else {
+ auto status = m_activation_wait_or_shutdown.wait(std::chrono::milliseconds(0));
+ if (HAILO_SHUTDOWN_EVENT_SIGNALED == status) {
+ return make_unexpected(HAILO_SHUTDOWN_EVENT_SIGNALED);
+ }
}
- CHECK_SUCCESS_AS_EXPECTED(status);
MemoryView buffer_view(buffer.value().as_view());
m_duration_collector.start_measurement();
- status = m_stream.read(buffer_view);
+ auto status = m_stream.read(buffer_view);
m_duration_collector.complete_measurement();
if (HAILO_INVALID_FRAME == status) {
m_stream.increase_invalid_frames_count(1);
hailo_status HwWriteElement::flush()
{
- hailo_status status = m_got_flush_event->wait(std::chrono::milliseconds(HAILO_DEFAULT_VSTREAM_TIMEOUT_MS));
+ hailo_status status = m_got_flush_event->wait(m_stream.get_timeout());
CHECK_SUCCESS(status);
status = m_got_flush_event->reset();
std::vector<std::shared_ptr<PipelineElement>> elements;
std::vector<InputVStream> vstreams;
- auto network_group_activated_event = input_stream.get_network_group_activated_event();
+ EventPtr network_group_activated_event = nullptr;
+ if (!input_stream.is_scheduled()) {
+ network_group_activated_event = input_stream.get_network_group_activated_event();
+ }
auto shutdown_event = Event::create_shared(Event::State::not_signalled);
CHECK_AS_EXPECTED(nullptr != shutdown_event, HAILO_OUT_OF_HOST_MEMORY);
std::vector<std::shared_ptr<PipelineElement>> elements;
std::vector<OutputVStream> vstreams;
- auto network_group_activated_event = output_stream.get_network_group_activated_event();
+ EventPtr network_group_activated_event = nullptr;
+ if (!output_stream.is_scheduled()) {
+ network_group_activated_event = output_stream.get_network_group_activated_event();
+ }
auto shutdown_event = Event::create_shared(Event::State::not_signalled);
CHECK_AS_EXPECTED(nullptr != shutdown_event, HAILO_OUT_OF_HOST_MEMORY);
output_stream.set_timeout(std::chrono::milliseconds(HAILO_INFINITE));
hw_read_queue_elem->get()->set_timeout(std::chrono::milliseconds(HAILO_INFINITE));
- auto vstream = OutputVStream::create(vstream_info->second, vstream_params, post_infer_queue_elem.release(),
- std::move(elements), std::move(pipeline_status), shutdown_event, network_group_activated_event, pipeline_latency_accumulator.release());
+ auto vstream = OutputVStream::create(vstream_info->second, vstream_params, post_infer_queue_elem.release(), std::move(elements),
+ std::move(pipeline_status), shutdown_event, network_group_activated_event, pipeline_latency_accumulator.release());
CHECK_EXPECTED(vstream);
vstreams.emplace_back(vstream.release());
} else {
base_elements.push_back(demux_elem.value());
CHECK_SUCCESS(PipelinePad::link_pads(hw_read_elem, demux_elem.value()));
- auto network_group_activated_event = output_stream.get_network_group_activated_event();
+ EventPtr network_group_activated_event = nullptr;
+ if (!output_stream.is_scheduled()) {
+ network_group_activated_event = output_stream.get_network_group_activated_event();
+ }
uint32_t i = 0;
for (auto &edge_info : demuxer_ptr->get_edges_stream_info()) {
current_vstream_elements.push_back(post_infer_queue_elem.value());
CHECK_SUCCESS(PipelinePad::link_pads(post_infer_elem.value(), post_infer_queue_elem.value()));
- auto vstream = OutputVStream::create(vstream_info->second, vstream_params, post_infer_queue_elem.release(),
- std::move(current_vstream_elements), std::move(pipeline_status_copy), shutdown_event, network_group_activated_event,
- pipeline_latency_accumulator.release());
+ auto vstream = OutputVStream::create(vstream_info->second, vstream_params, post_infer_queue_elem.release(), std::move(current_vstream_elements),
+ std::move(pipeline_status_copy), shutdown_event, network_group_activated_event, pipeline_latency_accumulator.release());
CHECK_EXPECTED_AS_STATUS(vstream);
vstreams.emplace_back(vstream.release());
} else {
current_vstream_elements.push_back(user_copy_elem.value());
CHECK_SUCCESS(PipelinePad::link_pads(demux_queue_elem.value(), user_copy_elem.value()));
- auto vstream = OutputVStream::create(vstream_info->second, vstream_params, user_copy_elem.release(),
- std::move(current_vstream_elements), std::move(pipeline_status_copy), shutdown_event, network_group_activated_event,
- pipeline_latency_accumulator.release());
+ auto vstream = OutputVStream::create(vstream_info->second, vstream_params, user_copy_elem.release(), std::move(current_vstream_elements),
+ std::move(pipeline_status_copy), shutdown_event, network_group_activated_event, pipeline_latency_accumulator.release());
CHECK_EXPECTED_AS_STATUS(vstream);
vstreams.emplace_back(vstream.release());
}
auto should_transform = OutputTransformContext::is_transformation_required({}, src_stream_format, {},
vstreams_params.user_buffer_format, vstream_info->second.quant_info);
+
+ EventPtr network_group_activated_event = nullptr;
+ if (!output_streams[0].get().is_scheduled()) {
+ network_group_activated_event = output_streams[0].get().get_network_group_activated_event();
+ }
if (should_transform) {
auto nms_queue_elem = PullQueueElement::create(
elements.push_back(post_infer_queue_elem.value());
CHECK_SUCCESS(PipelinePad::link_pads(post_infer_elem.value(), post_infer_queue_elem.value()));
- auto vstream = OutputVStream::create(vstream_info->second, vstreams_params, post_infer_queue_elem.release(),
- std::move(elements), std::move(pipeline_status), shutdown_event, output_streams[0].get().get_network_group_activated_event(),
- pipeline_latency_accumulator.release());
+ auto vstream = OutputVStream::create(vstream_info->second, vstreams_params, post_infer_queue_elem.release(), std::move(elements),
+ std::move(pipeline_status), shutdown_event, network_group_activated_event, pipeline_latency_accumulator.release());
CHECK_EXPECTED_AS_STATUS(vstream);
vstreams.emplace_back(vstream.release());
} else {
- auto vstream = OutputVStream::create(vstream_info->second, vstreams_params, nms_elem.release(),
- std::move(elements), std::move(pipeline_status), shutdown_event, output_streams[0].get().get_network_group_activated_event(),
- pipeline_latency_accumulator.release());
+ auto vstream = OutputVStream::create(vstream_info->second, vstreams_params, nms_elem.release(), std::move(elements),
+ std::move(pipeline_status), shutdown_event, network_group_activated_event, pipeline_latency_accumulator.release());
CHECK_EXPECTED_AS_STATUS(vstream);
vstreams.emplace_back(vstream.release());
}
cmake_minimum_required(VERSION 3.0.0)
project(hailort_prebuild)
-set(HAILO_PRE_BUILD_EXTERNAL_DIR ${CMAKE_CURRENT_LIST_DIR}/external)
-include(../libhailort/cmake/execute_cmake.cmake)
-message("Downloading dependencies to ${HAILO_EXTERNAL_DIR} ...")
-execute_cmake(
- SOURCE_DIR "${HAILO_PRE_BUILD_EXTERNAL_DIR}"
- BUILD_DIR "${HAILO_PRE_BUILD_EXTERNAL_DIR}/build"
- CONFIGURE_ARGS "-DHAILO_EXTERNAL_DIR=${HAILO_EXTERNAL_DIR}"
-)
-message("Finished downloading dependencies")
+if(NOT HAILO_OFFLINE_COMPILATION)
+ set(HAILO_PRE_BUILD_EXTERNAL_DIR ${CMAKE_CURRENT_LIST_DIR}/external)
+ include(../libhailort/cmake/execute_cmake.cmake)
+ message("Downloading dependencies to ${HAILO_EXTERNAL_DIR} ...")
+ execute_cmake(
+ SOURCE_DIR "${HAILO_PRE_BUILD_EXTERNAL_DIR}"
+ BUILD_DIR "${HAILO_PRE_BUILD_EXTERNAL_DIR}/build"
+ CONFIGURE_ARGS "-DHAILO_EXTERNAL_DIR=${HAILO_EXTERNAL_DIR}"
+ )
+ message("Finished downloading dependencies")
+else()
+ message("Offline compilation, skipped dependencies download")
+endif()
add_subdirectory(tools)
\ No newline at end of file
)
endfunction()
-git_clone(pybind11 https://github.com/pybind/pybind11.git 502ffe50a9f22c04637bbc8ec0019488458ba948)
+git_clone(pybind11 https://github.com/pybind/pybind11.git 8de7772cc72daca8e947b79b83fea46214931604)
git_clone(Catch2 https://github.com/catchorg/Catch2.git c4e3767e265808590986d5db6ca1b5532a7f3d13)
git_clone(CLI11 https://github.com/CLIUtils/CLI11.git 706b14fb14444e68ace232eb9a0ef106bf99343b)
git_clone(spdlog https://github.com/gabime/spdlog.git e2789531912a5c6ab28a90387f97c52963eec08a)
git_clone(readerwriterqueue https://github.com/cameron314/readerwriterqueue.git 435e36540e306cac40fcfeab8cc0a22d48464509)
git_clone(json https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent.git 391786c6c3abdd3eeb993a3154f1f2a4cfe137a0)
git_clone(DotWriter https://github.com/hailo-ai/DotWriter.git e5fa8f281adca10dd342b1d32e981499b8681daf)
-git_clone(benchmark https://github.com/google/benchmark.git f91b6b42b1b9854772a90ae9501464a161707d1e)
\ No newline at end of file
+git_clone(benchmark https://github.com/google/benchmark.git f91b6b42b1b9854772a90ae9501464a161707d1e)
+git_clone(pevents https://github.com/neosmart/pevents.git 1209b1fd1bd2e75daab4380cf43d280b90b45366)
+git_clone(microprofile https://github.com/jonasmr/microprofile 03c34f96840defe0f4c196309628815d02b98059)
:: cmd
@ECHO OFF
set BASE_URI=https://hailo-hailort.s3.eu-west-2.amazonaws.com
-set HRT_VERSION=4.6.0
+set HRT_VERSION=4.8.0
set REMOTE_HEF_DIR=Hailo8/%HRT_VERSION%/HEFS
set LOCAL_EXAMPLES_HEF_DIR=..\libhailort\examples\hefs
set LOCAL_TUTORIALS_HEF_DIR=..\libhailort\bindings\python\platform\tutorials\hefs
set -e
readonly BASE_URI="https://hailo-hailort.s3.eu-west-2.amazonaws.com"
-readonly HRT_VERSION=4.6.0
+readonly HRT_VERSION=4.8.0
readonly REMOTE_HEF_DIR="Hailo8/${HRT_VERSION}/HEFS"
readonly LOCAL_EXAMPLES_HEF_DIR="../libhailort/examples/hefs"
readonly LOCAL_TUTORIALS_HEF_DIR="../libhailort/bindings/python/platform/tutorials/hefs/"