text: // ======================================================================== //
  // Copyright 2009-2018 Intel Corporation                                    //
  //                                                                          //
  // Licensed under the Apache License, Version 2.0 (the "License");          //
  // you may not use this file except in compliance with the License.         //
  // You may obtain a copy of the License at                                  //
  //                                                                          //
  //     http://www.apache.org/licenses/LICENSE-2.0                           //
  //                                                                          //
  // Unless required by applicable law or agreed to in writing, software      //
  // distributed under the License is distributed on an "AS IS" BASIS,        //
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
  // See the License for the specific language governing permissions and      //
  // limitations under the License.                                           //
  // ======================================================================== //
  
  #include "state.h"
  #include "../../common/lexers/streamfilters.h"
  
  namespace embree
  {
    MutexSys g_printMutex;
  
    State::ErrorHandler State::g_errorHandler;
  
    State::ErrorHandler::ErrorHandler()
      : thread_error(createTls()) {}
  
    State::ErrorHandler::~ErrorHandler()
    {
      Lock<MutexSys> lock(errors_mutex);
      for (size_t i=0; i<thread_errors.size(); i++)
        delete thread_errors[i];
      destroyTls(thread_error);
      thread_errors.clear();
    }
  
    RTCError* State::ErrorHandler::error() 
    {
      RTCError* stored_error = (RTCError*) getTls(thread_error);
      if (stored_error) return stored_error;
  
      Lock<MutexSys> lock(errors_mutex);
      stored_error = new RTCError(RTC_NO_ERROR);
      thread_errors.push_back(stored_error);
      setTls(thread_error,stored_error);
      return stored_error;
    }
  
    State::State (bool singledevice) 
      : enabled_cpu_features(getCPUFeatures()),
        enabled_builder_cpu_features(enabled_cpu_features)
    {
      tri_accel = "default";
      tri_builder = "default";
      tri_traverser = "default";
      
      tri_accel_mb = "default";
      tri_builder_mb = "default";
      tri_traverser_mb = "default";
  
      quad_accel = "default";
      quad_builder = "default";
      quad_traverser = "default";
  
      quad_accel_mb = "default";
      quad_builder_mb = "default";
      quad_traverser_mb = "default";
  
      line_accel = "default";
      line_builder = "default";
      line_traverser = "default";
  
      line_accel_mb = "default";
      line_builder_mb = "default";
      line_traverser_mb = "default";
      
      hair_accel = "default";
      hair_builder = "default";
      hair_traverser = "default";
  
      hair_accel_mb = "default";
      hair_builder_mb = "default";
      hair_traverser_mb = "default";
  
      object_accel = "default";
      object_builder = "default";
      object_accel_min_leaf_size = 1;
      object_accel_max_leaf_size = 1;
  
      object_accel_mb = "default";
      object_builder_mb = "default";
      object_accel_mb_min_leaf_size = 1;
      object_accel_mb_max_leaf_size = 1;
  
      max_spatial_split_replications = 2.0f;
  
      tessellation_cache_size = 128*1024*1024;
  
      /* large default cache size only for old mode single device mode */
  #if defined(__X86_64__)
        if (singledevice) tessellation_cache_size = 1024*1024*1024;
  #else
        if (singledevice) tessellation_cache_size = 128*1024*1024;
  #endif
  
      subdiv_accel = "default";
      subdiv_accel_mb = "default";
  
      instancing_open_min = 0;
      instancing_block_size = 0;
      instancing_open_factor = 8.0f; 
      instancing_open_max_depth = 32;
      instancing_open_max = 50000000;
  
      ignore_config_files = false;
      float_exceptions = false;
      scene_flags = -1;
      verbose = 0;
      benchmark = 0;
  
      numThreads = 0;
  #if TASKING_INTERNAL
      set_affinity = true;
  #else
      set_affinity = false;
  #endif
      /* per default enable affinity on KNL */
      if (hasISA(AVX512KNL)) set_affinity = true;
  
      start_threads = false;
      enable_selockmemoryprivilege = false;
  #if defined(__LINUX__)
      hugepages = true;
  #else
      hugepages = false;
  #endif
      hugepages_success = true;
  
      alloc_main_block_size = 0;
      alloc_num_main_slots = 0;
      alloc_thread_block_size = 0;
      alloc_single_thread_alloc = -1;
  
      error_function = nullptr;
      error_function2 = nullptr;
      error_function_userptr = nullptr;
  
      memory_monitor_function = nullptr;
      memory_monitor_function2 = nullptr;
      memory_monitor_userptr = nullptr;
    }
  
    State::~State() {
    }
  
    bool State::hasISA(const int isa) {
      return (enabled_cpu_features & isa) == isa;
    }
  
    void State::verify()
    {
      /* verify that calculations stay in range */
      assert(rcp(min_rcp_input)*FLT_LARGE+FLT_LARGE < 0.01f*FLT_MAX);
  
      /* here we verify that CPP files compiled for a specific ISA only
       * call that same or lower ISA version of non-inlined class member
       * functions */
  #if defined(DEBUG)
  #if defined(EMBREE_TARGET_SSE2)
      assert(sse2::getISA() <= SSE2);
  #endif
  #if defined(EMBREE_TARGET_SSE42)
      assert(sse42::getISA() <= SSE42);
  #endif
  #if defined(EMBREE_TARGET_AVX)
      assert(avx::getISA() <= AVX);
  #endif
  #if defined(EMBREE_TARGET_AVX2)
      assert(avx2::getISA() <= AVX2);
  #endif
  #if defined (EMBREE_TARGET_AVX512KNL)
      assert(avx512knl::getISA() <= AVX512KNL);
  #endif
  #if defined (EMBREE_TARGET_AVX512SKX)
      assert(avx512skx::getISA() <= AVX512SKX);
  #endif
  #endif
    }
  
    const char* symbols[3] = { "=", ",", "|" };
  
     bool State::parseFile(const FileName& fileName)
    {
      FILE* f = fopen(fileName.c_str(),"r");
      if (!f) return false;
      Ref<Stream<int> > file = new FileStream(f,fileName);
      
      std::vector<std::string> syms;
      for (size_t i=0; i<sizeof(symbols)/sizeof(void*); i++) 
        syms.push_back(symbols[i]);
      
      Ref<TokenStream> cin = new TokenStream(new LineCommentFilter(file,"#"),
                                             TokenStream::alpha+TokenStream::ALPHA+TokenStream::numbers+"_.",
                                             TokenStream::separators,syms);
      parse(cin);
      return true;
    }
  
    void State::parseString(const char* cfg)
    {
      if (cfg == nullptr) return;
  
      std::vector<std::string> syms;
      for (size_t i=0; i<sizeof(symbols)/sizeof(void*); i++) 
        syms.push_back(symbols[i]);
      
      Ref<TokenStream> cin = new TokenStream(new StrStream(cfg),
                                             TokenStream::alpha+TokenStream::ALPHA+TokenStream::numbers+"_.",
                                             TokenStream::separators,syms);
      parse(cin);
    }
    
    int string_to_cpufeatures(const std::string& isa)
    {
      if      (isa == "sse" ) return SSE;
      else if (isa == "sse2") return SSE2;
      else if (isa == "sse3") return SSE3;
      else if (isa == "ssse3") return SSSE3;
      else if (isa == "sse41") return SSE41;
      else if (isa == "sse4.1") return SSE41;
      else if (isa == "sse42") return SSE42;
      else if (isa == "sse4.2") return SSE42;
      else if (isa == "avx") return AVX;
      else if (isa == "avxi") return AVXI;
      else if (isa == "avx2") return AVX2;
      else if (isa == "avx512knl") return AVX512KNL;
      else if (isa == "avx512skx") return AVX512SKX;
      else return SSE2;
    }
  
    void State::parse(Ref<TokenStream> cin)
    {
      /* parse until end of stream */
      while (cin->peek() != Token::Eof())
      {
        const Token tok = cin->get();
  
        if (tok == Token::Id("threads") && cin->trySymbol("=")) 
          numThreads = cin->get().Int();
  
        else if (tok == Token::Id("set_affinity")&& cin->trySymbol("=")) 
          set_affinity = cin->get().Int();
  
        else if (tok == Token::Id("affinity")&& cin->trySymbol("=")) 
          set_affinity = cin->get().Int();
        
        else if (tok == Token::Id("start_threads")&& cin->trySymbol("=")) 
          start_threads = cin->get().Int();
        
        else if (tok == Token::Id("isa") && cin->trySymbol("=")) {
          std::string isa = toLowerCase(cin->get().Identifier());
          enabled_cpu_features = string_to_cpufeatures(isa);
          enabled_builder_cpu_features = enabled_cpu_features;
        }
  
        else if (tok == Token::Id("max_isa") && cin->trySymbol("=")) {
          std::string isa = toLowerCase(cin->get().Identifier());
          enabled_cpu_features &= string_to_cpufeatures(isa);
          enabled_builder_cpu_features &= enabled_cpu_features;
        }
  
        else if (tok == Token::Id("max_builder_isa") && cin->trySymbol("=")) {
          std::string isa = toLowerCase(cin->get().Identifier());
          enabled_builder_cpu_features &= string_to_cpufeatures(isa);
        }
  
        else if (tok == Token::Id("enable_selockmemoryprivilege") && cin->trySymbol("=")) {
          enable_selockmemoryprivilege = cin->get().Int();
        }
        else if (tok == Token::Id("hugepages") && cin->trySymbol("=")) {
          hugepages = cin->get().Int();
        }
  
        else if (tok == Token::Id("ignore_config_files") && cin->trySymbol("="))
          ignore_config_files = cin->get().Int();
        else if (tok == Token::Id("float_exceptions") && cin->trySymbol("=")) 
          float_exceptions = cin->get().Int();
  
        else if ((tok == Token::Id("tri_accel") || tok == Token::Id("accel")) && cin->trySymbol("="))
          tri_accel = cin->get().Identifier();
        else if ((tok == Token::Id("tri_builder") || tok == Token::Id("builder")) && cin->trySymbol("="))
          tri_builder = cin->get().Identifier();
        else if ((tok == Token::Id("tri_traverser") || tok == Token::Id("traverser")) && cin->trySymbol("="))
          tri_traverser = cin->get().Identifier();
       
        else if ((tok == Token::Id("tri_accel_mb") || tok == Token::Id("accel_mb")) && cin->trySymbol("="))
          tri_accel_mb = cin->get().Identifier();
        else if ((tok == Token::Id("tri_builder_mb") || tok == Token::Id("builder_mb")) && cin->trySymbol("="))
          tri_builder_mb = cin->get().Identifier();
        else if ((tok == Token::Id("tri_traverser_mb") || tok == Token::Id("traverser_mb")) && cin->trySymbol("="))
          tri_traverser_mb = cin->get().Identifier();
  
        else if ((tok == Token::Id("quad_accel")) && cin->trySymbol("="))
          quad_accel = cin->get().Identifier();
        else if ((tok == Token::Id("quad_builder")) && cin->trySymbol("="))
          quad_builder = cin->get().Identifier();
        else if ((tok == Token::Id("quad_traverser")) && cin->trySymbol("="))
          quad_traverser = cin->get().Identifier();
  
        else if ((tok == Token::Id("quad_accel_mb")) && cin->trySymbol("="))
          quad_accel_mb = cin->get().Identifier();
        else if ((tok == Token::Id("quad_builder_mb")) && cin->trySymbol("="))
          quad_builder_mb = cin->get().Identifier();
        else if ((tok == Token::Id("quad_traverser_mb")) && cin->trySymbol("="))
          quad_traverser_mb = cin->get().Identifier();
  
        else if ((tok == Token::Id("line_accel")) && cin->trySymbol("="))
          line_accel = cin->get().Identifier();
        else if ((tok == Token::Id("line_builder")) && cin->trySymbol("="))
          line_builder = cin->get().Identifier();
        else if ((tok == Token::Id("line_traverser")) && cin->trySymbol("="))
          line_traverser = cin->get().Identifier();
  
        else if ((tok == Token::Id("line_accel_mb")) && cin->trySymbol("="))
          line_accel_mb = cin->get().Identifier();
        else if ((tok == Token::Id("line_builder_mb")) && cin->trySymbol("="))
          line_builder_mb = cin->get().Identifier();
        else if ((tok == Token::Id("line_traverser_mb")) && cin->trySymbol("="))
          line_traverser_mb = cin->get().Identifier();
        
        else if (tok == Token::Id("hair_accel") && cin->trySymbol("="))
          hair_accel = cin->get().Identifier();
        else if (tok == Token::Id("hair_builder") && cin->trySymbol("="))
          hair_builder = cin->get().Identifier();
        else if (tok == Token::Id("hair_traverser") && cin->trySymbol("="))
          hair_traverser = cin->get().Identifier();
  
        else if (tok == Token::Id("hair_accel_mb") && cin->trySymbol("="))
          hair_accel_mb = cin->get().Identifier();
        else if (tok == Token::Id("hair_builder_mb") && cin->trySymbol("="))
          hair_builder_mb = cin->get().Identifier();
        else if (tok == Token::Id("hair_traverser_mb") && cin->trySymbol("="))
          hair_traverser_mb = cin->get().Identifier();
  
        else if (tok == Token::Id("object_accel") && cin->trySymbol("="))
          object_accel = cin->get().Identifier();
        else if (tok == Token::Id("object_builder") && cin->trySymbol("="))
          object_builder = cin->get().Identifier();
        else if (tok == Token::Id("object_accel_min_leaf_size") && cin->trySymbol("="))
          object_accel_min_leaf_size = cin->get().Int();
        else if (tok == Token::Id("object_accel_max_leaf_size") && cin->trySymbol("="))
          object_accel_max_leaf_size = cin->get().Int();
  
        else if (tok == Token::Id("object_accel_mb") && cin->trySymbol("="))
          object_accel_mb = cin->get().Identifier();
        else if (tok == Token::Id("object_builder_mb") && cin->trySymbol("="))
          object_builder_mb = cin->get().Identifier();
        else if (tok == Token::Id("object_accel_mb_min_leaf_size") && cin->trySymbol("="))
          object_accel_mb_min_leaf_size = cin->get().Int();
        else if (tok == Token::Id("object_accel_mb_max_leaf_size") && cin->trySymbol("="))
          object_accel_mb_max_leaf_size = cin->get().Int();
  
        else if (tok == Token::Id("instancing_open_min") && cin->trySymbol("="))
          instancing_open_min = cin->get().Int();
        else if (tok == Token::Id("instancing_block_size") && cin->trySymbol("=")) {
          instancing_block_size = cin->get().Int();
          instancing_open_factor = 0.0f;
        }
        else if (tok == Token::Id("instancing_open_max_depth") && cin->trySymbol("="))
          instancing_open_max_depth = cin->get().Int();
        else if (tok == Token::Id("instancing_open_factor") && cin->trySymbol("=")) {
          instancing_block_size = 0;
          instancing_open_factor = cin->get().Float();
        }
        else if (tok == Token::Id("instancing_open_max") && cin->trySymbol("="))
          instancing_open_max = cin->get().Int();
  
        else if (tok == Token::Id("subdiv_accel") && cin->trySymbol("="))
          subdiv_accel = cin->get().Identifier();
        else if (tok == Token::Id("subdiv_accel_mb") && cin->trySymbol("="))
          subdiv_accel_mb = cin->get().Identifier();
        
        else if (tok == Token::Id("verbose") && cin->trySymbol("="))
          verbose = cin->get().Int();
        else if (tok == Token::Id("benchmark") && cin->trySymbol("="))
          benchmark = cin->get().Int();
        
        else if (tok == Token::Id("flags")) {
          scene_flags = 0;
          if (cin->trySymbol("=")) {
            do {
              Token flag = cin->get();
              if      (flag == Token::Id("static") ) scene_flags |= RTC_SCENE_STATIC;
              else if (flag == Token::Id("dynamic")) scene_flags |= RTC_SCENE_DYNAMIC;
              else if (flag == Token::Id("compact")) scene_flags |= RTC_SCENE_COMPACT;
              else if (flag == Token::Id("coherent")) scene_flags |= RTC_SCENE_COHERENT;
              else if (flag == Token::Id("incoherent")) scene_flags |= RTC_SCENE_INCOHERENT;
              else if (flag == Token::Id("high_quality")) scene_flags |= RTC_SCENE_HIGH_QUALITY;
              else if (flag == Token::Id("robust")) scene_flags |= RTC_SCENE_ROBUST;
            } while (cin->trySymbol("|"));
          }
        }
  
        else if (tok == Token::Id("max_spatial_split_replications") && cin->trySymbol("="))
          max_spatial_split_replications = cin->get().Float();
  
        else if (tok == Token::Id("tessellation_cache_size") && cin->trySymbol("="))
          tessellation_cache_size = size_t(cin->get().Float()*1024.0f*1024.0f);
        else if (tok == Token::Id("cache_size") && cin->trySymbol("="))
          tessellation_cache_size = size_t(cin->get().Float()*1024.0f*1024.0f);
  
        else if (tok == Token::Id("alloc_main_block_size") && cin->trySymbol("="))
          alloc_main_block_size = cin->get().Int();
         else if (tok == Token::Id("alloc_num_main_slots") && cin->trySymbol("="))
          alloc_num_main_slots = cin->get().Int();
         else if (tok == Token::Id("alloc_thread_block_size") && cin->trySymbol("="))
           alloc_thread_block_size = cin->get().Int();
         else if (tok == Token::Id("alloc_single_thread_alloc") && cin->trySymbol("="))
           alloc_single_thread_alloc = cin->get().Int();
  
        cin->trySymbol(","); // optional , separator
      }
    }
  
    bool State::verbosity(size_t N) {
      return N <= verbose;
    }
  
    void State::print()
    {
      std::cout << "general:" << std::endl;
      std::cout << "  build threads = " << numThreads   << std::endl;
      std::cout << "  start_threads = " << start_threads << std::endl;
      std::cout << "  affinity      = " << set_affinity << std::endl;
      
      std::cout << "  hugepages     = ";
      if (!hugepages) std::cout << "disabled" << std::endl;
      else if (hugepages_success) std::cout << "enabled" << std::endl;
      else std::cout << "failed" << std::endl;
  
      std::cout << "  verbosity     = " << verbose << std::endl;
      std::cout << "  cache_size    = " << float(tessellation_cache_size)*1E-6 << " MB" << std::endl;
      std::cout << "  max_spatial_split_replications = " << max_spatial_split_replications << std::endl;
      
      std::cout << "triangles:" << std::endl;
      std::cout << "  accel         = " << tri_accel << std::endl;
      std::cout << "  builder       = " << tri_builder << std::endl;
      std::cout << "  traverser     = " << tri_traverser << std::endl;
          
      std::cout << "motion blur triangles:" << std::endl;
      std::cout << "  accel         = " << tri_accel_mb << std::endl;
      std::cout << "  builder       = " << tri_builder_mb << std::endl;
      std::cout << "  traverser     = " << tri_traverser_mb << std::endl;
  
      std::cout << "quads:" << std::endl;
      std::cout << "  accel         = " << quad_accel << std::endl;
      std::cout << "  builder       = " << quad_builder << std::endl;
      std::cout << "  traverser     = " << quad_traverser << std::endl;
  
      std::cout << "motion blur quads:" << std::endl;
      std::cout << "  accel         = " << quad_accel_mb << std::endl;
      std::cout << "  builder       = " << quad_builder_mb << std::endl;
      std::cout << "  traverser     = " << quad_traverser_mb << std::endl;
  
      std::cout << "line segments:" << std::endl;
      std::cout << "  accel         = " << line_accel << std::endl;
      std::cout << "  builder       = " << line_builder << std::endl;
      std::cout << "  traverser     = " << line_traverser << std::endl;
  
      std::cout << "motion blur line segments:" << std::endl;
      std::cout << "  accel         = " << line_accel_mb << std::endl;
      std::cout << "  builder       = " << line_builder_mb << std::endl;
      std::cout << "  traverser     = " << line_traverser_mb << std::endl;
      
      std::cout << "hair:" << std::endl;
      std::cout << "  accel         = " << hair_accel << std::endl;
      std::cout << "  builder       = " << hair_builder << std::endl;
      std::cout << "  traverser     = " << hair_traverser << std::endl;
  
      std::cout << "motion blur hair:" << std::endl;
      std::cout << "  accel         = " << hair_accel_mb << std::endl;
      std::cout << "  builder       = " << hair_builder_mb << std::endl;
      std::cout << "  traverser     = " << hair_traverser_mb << std::endl;
      
      std::cout << "subdivision surfaces:" << std::endl;
      std::cout << "  accel         = " << subdiv_accel << std::endl;
  
      std::cout << "object_accel:" << std::endl;
      std::cout << "  min_leaf_size = " << object_accel_min_leaf_size << std::endl;
      std::cout << "  max_leaf_size = " << object_accel_max_leaf_size << std::endl;
  
      std::cout << "object_accel_mb:" << std::endl;
      std::cout << "  min_leaf_size = " << object_accel_mb_min_leaf_size << std::endl;
      std::cout << "  max_leaf_size = " << object_accel_mb_max_leaf_size << std::endl;
    }
  }
  