<commit_before>/**
 * This file is part of node-kdtree, a node.js Addon for working with kd-trees.
 * Copyright (C) 2011 Justin Ethier <justinethier@github>
 *
 * Please use github to submit patches and bug reports:
 * https://github.com/justinethier/node-kdtree
 */

// TODO: publish via npm. see: https://github.com/isaacs/npm/blob/master/doc/developers.md#readme
//
#include <v8.h>
#include <node.h>
#include <node_events.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <kdtree.h>

using namespace v8;
using namespace node;

class KDTree : public ObjectWrap {
  public:
    static void
    Initialize (v8::Handle<v8::Object> target){
        HandleScope scope;

        Local<FunctionTemplate> t = FunctionTemplate::New(New);

        t->InstanceTemplate()->SetInternalFieldCount(1);
        t->SetClassName(String::NewSymbol("KDTree"));

        NODE_SET_PROTOTYPE_METHOD(t, "test", Test); // TODO: this will go away...
        NODE_SET_PROTOTYPE_METHOD(t, "insert", Insert);
        NODE_SET_PROTOTYPE_METHOD(t, "nearest", Nearest);
//        NODE_SET_PROTOTYPE_METHOD(t, "nearestRange", NearestRange); // kd_nearest_range

        target->Set(String::NewSymbol("KDTree"), t->GetFunction());
    }

    // TODO: allow insertion of (string?) data
    bool Insert(const double *pos, Handle<Value> data){
      return (kd_insert(kd_, pos, *data) == 0);
    }

    // Allow retrieval of (string?) data
    Handle<Value>
    Nearest(const double *pos){
      int rpos;
      void *pdata;
      kdres *results = kd_nearest(kd_, pos);
      Local<Array> rv = Array::New(dim_ + 1);

      if (results == NULL){}
      else{
        double *respos = (double *)(malloc(sizeof(double) * dim_));
        pdata = (void *)kd_res_item(results, respos);

        for(rpos = 0; rpos < dim_; rpos++){
          rv->Set(rpos, Number::New(respos[rpos]));
        }

// TODO: any way to get that data back?
Persistent<Value> hdata = Persistent<Value>::Persistent((Value *)pdata);
        rv->Set(dim_, hdata); // TODO: append data element here
//         Number::New( (void *)pdata ));
//        Number::New(respos[rpos]));

        free(respos);
        kd_res_free(results);
      }
      return rv;
    }

    int Test()
    {
       int i, vcount = 10;
       kdtree *kd;
       kdres *set;
    //   unsigned int msec, start;

       printf("inserting %d random vectors... ", vcount);
       fflush(stdout);

       kd = kd_create(3);

    //   start = get_msec();
       for(i=0; i<vcount; i++) {
               float x, y, z;
               x = ((float)rand() / RAND_MAX) * 200.0 - 100.0;
               y = ((float)rand() / RAND_MAX) * 200.0 - 100.0;
               z = ((float)rand() / RAND_MAX) * 200.0 - 100.0;

               assert(kd_insert3(kd, x, y, z, 0) == 0);
       }
    //   msec = get_msec() - start;
    //   printf("%.3f sec\n", (float)msec / 1000.0);

    //   start = get_msec();
       set = kd_nearest_range3(kd, 0, 0, 0, 100);
    //   msec = get_msec() - start;
    //
       i = kd_res_size(set);
       printf("range query returned %d items\n", kd_res_size(set));
       kd_res_free(set);

       kd_free(kd);
       return i;
    }

  protected:

    static Handle<Value>
    Insert(const Arguments& args){
        KDTree *kd = ObjectWrap::Unwrap<KDTree>(args.This());
        HandleScope scope;

      double *pos = (double *)(malloc(sizeof(double) * args.Length()));
      for (int i = 0; i < args.Length(); i++){
        pos[i] = args[i]->NumberValue();
      }

// TODO: pass data parameter down using a persistent handle?
// http://izs.me/v8-docs/classv8_1_1Persistent.html#_details
//
// TODO:
// if this is the case, need to pass as arg, then in Insert() need to
// validate that num args == dim_
//
      // TODO: may want to pass Length down, so class can assert == dim_
      Handle<Value> result = Boolean::New( kd->Insert(pos,
          Persistent<Value>::New(args[0]) // Test code, just stuff number as data for now...
                                    // Eventually will want API to allow an optional data arg.
                                    // If not specified, will default to something (null?)
          ) );
      free(pos);
      return result;
    }

    static Handle<Value>
    Nearest(const Arguments& args){
      KDTree *kd = ObjectWrap::Unwrap<KDTree>(args.This());
      HandleScope scope;

      double *pos = (double *)(malloc(sizeof(double) * args.Length()));
      for (int i = 0; i < args.Length(); i++){
        pos[i] = args[i]->NumberValue();
      }

      // TODO: may want to pass Length down, so class can assert == dim_
      Handle<Value> result = kd->Nearest(pos);

      free(pos);
      return result;
    }

// TODO:
//    static Handle<Value>
//    NearestRange(const Arguments& args){}

    static Handle<Value>
    New (const Arguments& args){
        HandleScope scope;

// TODO: an example of how to handle arguments to constructor
//Async *async = new Async(args[0]->Int32Value(), args[1]->Int32Value());

        int dimension = 3; // Default
        if (args.Length() > 0){
          dimension = args[3]->Int32Value();
        }

        KDTree *kd = new KDTree(dimension);
        kd->Wrap(args.This());

        return args.This();
    }

    KDTree (int dim) : ObjectWrap (){
        kd_ = kd_create(dim);
        dim_ = dim;
    }

    ~KDTree(){
      // TODO: need to call this to clean up allocated 'data' elements
      //       see the kdtree docs:
//      void kd_data_destructor(struct kdtree *tree, void (*destr)(void*));
        if (kd_ != NULL){
            kd_free(kd_);
        }
    }

    static Handle<Value>
    Test (const Arguments& args){
        KDTree *kd = ObjectWrap::Unwrap<KDTree>(args.This());

        HandleScope scope;

        int num = kd->Test();

        return Integer::New(num); // Undefined();
    }

  private:
    kdtree* kd_;
    int dim_;
};

extern "C" void
init (Handle<Object> target)
{
    HandleScope scope;
    KDTree::Initialize(target);
}

<commit_msg>Added storage of data<commit_after>/**
 * This file is part of node-kdtree, a node.js Addon for working with kd-trees.
 * Copyright (C) 2011 Justin Ethier <justinethier@github>
 *
 * Please use github to submit patches and bug reports:
 * https://github.com/justinethier/node-kdtree
 */

// TODO: publish via npm. see: https://github.com/isaacs/npm/blob/master/doc/developers.md#readme
//
#include <v8.h>
#include <node.h>
#include <node_events.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <kdtree.h>

using namespace v8;
using namespace node;

class KDTree : public ObjectWrap {
  public:
    static void
    Initialize (v8::Handle<v8::Object> target){
        HandleScope scope;

        Local<FunctionTemplate> t = FunctionTemplate::New(New);

        t->InstanceTemplate()->SetInternalFieldCount(1);
        t->SetClassName(String::NewSymbol("KDTree"));

        NODE_SET_PROTOTYPE_METHOD(t, "test", Test); // TODO: this will go away...
        NODE_SET_PROTOTYPE_METHOD(t, "insert", Insert);
        NODE_SET_PROTOTYPE_METHOD(t, "nearest", Nearest);
//        NODE_SET_PROTOTYPE_METHOD(t, "nearestRange", NearestRange); // kd_nearest_range

        target->Set(String::NewSymbol("KDTree"), t->GetFunction());
    }

    /**
     * Insert a set of points into the tree.
     *
     * An optional data argument is present as well;
     * if len == dim_, then the data param will be ignored.
     *
     * @param pos   An array of points
     * @param len   Number of points in the array
     * @param data  Optional data argument
     *
     * @return true if the point was inserted successfully, false otherwise
     */
    bool Insert(const double *pos, int len, Handle<Value> data){
      if (len == dim_)
        return (kd_insert(kd_, pos, NULL) == 0);
      return (kd_insert(kd_, pos, *data) == 0);
    }

    /**
     * Find the point nearest to the given point.
     *
     * @return An array containing the nearest point, or an empty array if no point is found.
     *         If a data element was provided for the nearest point, it will be the last
     *         member of the returned array.
     */
    Handle<Value>
    Nearest(const double *pos){
      int rpos;
      void *pdata;
      kdres *results = kd_nearest(kd_, pos);
      Local<Array> rv = Array::New(dim_ + 1);

      if (results != NULL) {
        double *respos = (double *)(malloc(sizeof(double) * dim_));
        pdata = (void *)kd_res_item(results, respos);

        for(rpos = 0; rpos < dim_; rpos++){
          rv->Set(rpos, Number::New(respos[rpos]));
        }

        // Append data element, if present
        if (pdata != NULL) {
          Persistent<Value> hdata = Persistent<Value>::Persistent((Value *)pdata);
          // TODO: somehow need to dispose of the persistent handle, and perhaps
          // allocate a new var with a local (?) handle
          rv->Set(dim_, hdata);
        }

        free(respos);
        kd_res_free(results);
      }
      return rv;
    }

    int Test()
    {
       int i, vcount = 10;
       kdtree *kd;
       kdres *set;
    //   unsigned int msec, start;

       printf("inserting %d random vectors... ", vcount);
       fflush(stdout);

       kd = kd_create(3);

    //   start = get_msec();
       for(i=0; i<vcount; i++) {
               float x, y, z;
               x = ((float)rand() / RAND_MAX) * 200.0 - 100.0;
               y = ((float)rand() / RAND_MAX) * 200.0 - 100.0;
               z = ((float)rand() / RAND_MAX) * 200.0 - 100.0;

               assert(kd_insert3(kd, x, y, z, 0) == 0);
       }
    //   msec = get_msec() - start;
    //   printf("%.3f sec\n", (float)msec / 1000.0);

    //   start = get_msec();
       set = kd_nearest_range3(kd, 0, 0, 0, 100);
    //   msec = get_msec() - start;
    //
       i = kd_res_size(set);
       printf("range query returned %d items\n", kd_res_size(set));
       kd_res_free(set);

       kd_free(kd);
       return i;
    }

  protected:

    /**
     * Wrapper for Insert()
     */
    static Handle<Value>
    Insert(const Arguments& args){
        KDTree *kd = ObjectWrap::Unwrap<KDTree>(args.This());
        HandleScope scope;

      double *pos = (double *)(malloc(sizeof(double) * args.Length()));
      for (int i = 0; i < args.Length(); i++){
        pos[i] = args[i]->NumberValue();
      }

      Handle<Value> result = Boolean::New( kd->Insert(pos, args.Length(),
          Persistent<Value>::New(args[ args.Length() - 1])));
            // Test code, just stuff number as data for now...
            // Eventually will want API to allow an optional data arg.
            // If not specified, will default to something (null?)
      free(pos);
      return result;
    }

    /**
     * Wrapper for Nearest()
     */
    static Handle<Value>
    Nearest(const Arguments& args){
      KDTree *kd = ObjectWrap::Unwrap<KDTree>(args.This());
      HandleScope scope;

      double *pos = (double *)(malloc(sizeof(double) * args.Length()));
      for (int i = 0; i < args.Length(); i++){
        pos[i] = args[i]->NumberValue();
      }

      // TODO: may want to pass Length down, so class can assert == dim_
      Handle<Value> result = kd->Nearest(pos);

      free(pos);
      return result;
    }

// TODO:
//    static Handle<Value>
//    NearestRange(const Arguments& args){}

    /**
     *
     */
    static Handle<Value>
    New (const Arguments& args){
        HandleScope scope;

// TODO: an example of how to handle arguments to constructor
//Async *async = new Async(args[0]->Int32Value(), args[1]->Int32Value());

        int dimension = 3; // Default
        if (args.Length() > 0){
          dimension = args[3]->Int32Value();
        }

        KDTree *kd = new KDTree(dimension);
        kd->Wrap(args.This());

        return args.This();
    }

    KDTree (int dim) : ObjectWrap (){
        kd_ = kd_create(dim);
        dim_ = dim;
    }

    ~KDTree(){
      // TODO: need to call this to clean up allocated 'data' elements
      //       see the kdtree docs:
//      void kd_data_destructor(struct kdtree *tree, void (*destr)(void*));
        if (kd_ != NULL){
            kd_free(kd_);
        }
    }

    static Handle<Value>
    Test (const Arguments& args){
        KDTree *kd = ObjectWrap::Unwrap<KDTree>(args.This());

        HandleScope scope;

        int num = kd->Test();

        return Integer::New(num); // Undefined();
    }

  private:
    kdtree* kd_;
    int dim_;
};

extern "C" void
init (Handle<Object> target)
{
    HandleScope scope;
    KDTree::Initialize(target);
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: listenerbase.cxx,v $
 *
 *  $Revision: 1.1 $
 *
 *  last change: $Author: jp $ $Date: 2000-11-14 18:52:13 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#pragma hdrstop

#ifndef DEBUG_HXX
#include <tools/debug.hxx>
#endif

#include "listenerbase.hxx"
#include "listeneriter.hxx"
#include "listener.hxx"
#include "broadcast.hxx"

SvtListenerBase::SvtListenerBase( SvtListener& rLst,
                                  SvtBroadcaster& rBroadcaster )
    : pBroadcaster( &rBroadcaster ), pListener( &rLst ),
    pLeft( 0 ), pRight( 0 )
{
    pNext = rLst.pBrdCastLst;
    rLst.pBrdCastLst = this;

    if( pBroadcaster->pRoot )
    {
        // set ever behind the root
        pRight = pBroadcaster->pRoot->pRight;
        pBroadcaster->pRoot->pRight = this;
        this->pLeft = pBroadcaster->pRoot;
        if( pRight )
            pRight->pLeft = this;
    }
    else
        pBroadcaster->pRoot = this;
}

SvtListenerBase::~SvtListenerBase()
{
    SvtListenerBase *pR = pRight, *pL = pLeft;
    if( pBroadcaster->pRoot )
        pBroadcaster->pRoot = pL ? pL : pR;

    if( pL )
        pL->pRight = pR;
    if( pR )
        pR->pLeft = pL;

    SvtListenerIter::RemoveListener( *this, pR );

    if( !pBroadcaster->pRoot )
        pBroadcaster->ListenersGone();
}

<commit_msg>INTEGRATION: CWS ooo20040509 (1.1.584); FILE MERGED 2004/05/06 12:28:03 waratah 1.1.584.1: #i1858# reorder definitions to match header bracket pragma that is not valid in gcc to clean up -Wall compile<commit_after>/*************************************************************************
 *
 *  $RCSfile: listenerbase.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2004-06-16 10:26:49 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef GCC
#pragma hdrstop
#endif

#ifndef DEBUG_HXX
#include <tools/debug.hxx>
#endif

#include "listenerbase.hxx"
#include "listeneriter.hxx"
#include "listener.hxx"
#include "broadcast.hxx"

SvtListenerBase::SvtListenerBase( SvtListener& rLst,
                                  SvtBroadcaster& rBroadcaster )
    : pLeft( 0 ), pRight( 0 ),
    pBroadcaster( &rBroadcaster ), pListener( &rLst )
{
    pNext = rLst.pBrdCastLst;
    rLst.pBrdCastLst = this;

    if( pBroadcaster->pRoot )
    {
        // set ever behind the root
        pRight = pBroadcaster->pRoot->pRight;
        pBroadcaster->pRoot->pRight = this;
        this->pLeft = pBroadcaster->pRoot;
        if( pRight )
            pRight->pLeft = this;
    }
    else
        pBroadcaster->pRoot = this;
}

SvtListenerBase::~SvtListenerBase()
{
    SvtListenerBase *pR = pRight, *pL = pLeft;
    if( pBroadcaster->pRoot )
        pBroadcaster->pRoot = pL ? pL : pR;

    if( pL )
        pL->pRight = pR;
    if( pR )
        pR->pLeft = pL;

    SvtListenerIter::RemoveListener( *this, pR );

    if( !pBroadcaster->pRoot )
        pBroadcaster->ListenersGone();
}

<|endoftext|>


<commit_before>#include "offline_cache_util.h"

#include "taichi/common/core.h"
#include "taichi/common/serialization.h"
#include "taichi/ir/snode.h"
#include "taichi/ir/transforms.h"
#include "taichi/program/compile_config.h"
#include "taichi/program/kernel.h"

#include "picosha2.h"

#include <vector>

namespace taichi {
namespace lang {

static std::vector<std::uint8_t> get_offline_cache_key_of_compile_config(
    CompileConfig *config) {
  TI_ASSERT(config);
  BinaryOutputSerializer serializer;
  serializer.initialize();
  serializer(config->arch);
  serializer(config->debug);
  serializer(config->cfg_optimization);
  serializer(config->check_out_of_bound);
  serializer(config->opt_level);
  serializer(config->external_optimization_level);
  serializer(config->packed);
  serializer(config->move_loop_invariant_outside_if);
  serializer(config->demote_dense_struct_fors);
  serializer(config->advanced_optimization);
  serializer(config->constant_folding);
  serializer(config->kernel_profiler);
  serializer(config->fast_math);
  serializer(config->flatten_if);
  serializer(config->make_thread_local);
  serializer(config->make_block_local);
  serializer(config->detect_read_only);
  serializer(config->default_fp->to_string());
  serializer(config->default_ip.to_string());
  if (arch_is_cpu(config->arch)) {
    serializer(config->default_cpu_block_dim);
    serializer(config->cpu_max_num_threads);
  } else if (arch_is_gpu(config->arch)) {
    serializer(config->default_gpu_block_dim);
    serializer(config->gpu_max_reg);
    serializer(config->saturating_grid_dim);
    serializer(config->cpu_max_num_threads);
  }
  serializer(config->ad_stack_size);
  serializer(config->default_ad_stack_size);
  serializer(config->random_seed);
  if (config->arch == Arch::cc) {
    serializer(config->cc_compile_cmd);
    serializer(config->cc_link_cmd);
  } else if (config->arch == Arch::opengl) {
    serializer(config->allow_nv_shader_extension);
    serializer(config->use_gles);
  }
  serializer(config->make_mesh_block_local);
  serializer(config->optimize_mesh_reordered_mapping);
  serializer(config->mesh_localize_to_end_mapping);
  serializer(config->mesh_localize_from_end_mapping);
  serializer(config->mesh_localize_all_attr_mappings);
  serializer(config->demote_no_access_mesh_fors);
  serializer(config->experimental_auto_mesh_local);
  serializer(config->auto_mesh_local_default_occupacy);
  serializer.finalize();

  return serializer.data;
}

static void get_offline_cache_key_of_snode_impl(
    SNode *snode,
    BinaryOutputSerializer &serializer,
    std::unordered_set<int> &visited) {
  if (auto iter = visited.find(snode->id); iter != visited.end()) {
    serializer(snode->id);  // Use snode->id as placeholder to identify a snode
    return;
  }

  visited.insert(snode->id);
  for (auto &c : snode->ch) {
    get_offline_cache_key_of_snode_impl(c.get(), serializer, visited);
  }
  for (int i = 0; i < taichi_max_num_indices; ++i) {
    auto &extractor = snode->extractors[i];
    serializer(extractor.num_elements_from_root);
    serializer(extractor.shape);
    serializer(extractor.acc_shape);
    serializer(extractor.num_bits);
    serializer(extractor.acc_offset);
    serializer(extractor.active);
  }
  serializer(snode->index_offsets);
  serializer(snode->num_active_indices);
  serializer(snode->physical_index_position);
  serializer(snode->id);
  serializer(snode->depth);
  serializer(snode->name);
  serializer(snode->num_cells_per_container);
  serializer(snode->total_num_bits);
  serializer(snode->total_bit_start);
  serializer(snode->chunk_size);
  serializer(snode->cell_size_bytes);
  serializer(snode->offset_bytes_in_parent_cell);
  serializer(snode->dt->to_string());
  serializer(snode->has_ambient);
  if (!snode->ambient_val.dt->is_primitive(PrimitiveTypeID::unknown)) {
    serializer(snode->ambient_val.stringify());
  }
  if (snode->grad_info && !snode->grad_info->is_primal()) {
    if (auto *adjoint_snode = snode->grad_info->adjoint_snode()) {
      get_offline_cache_key_of_snode_impl(adjoint_snode, serializer, visited);
    }
    if (auto *dual_snode = snode->grad_info->dual_snode()) {
      get_offline_cache_key_of_snode_impl(dual_snode, serializer, visited);
    }
  }
  if (snode->physical_type) {
    serializer(snode->physical_type->to_string());
  }
  serializer(snode->id_in_bit_struct);
  serializer(snode->is_bit_level);
  serializer(snode->is_path_all_dense);
  serializer(snode->node_type_name);
  serializer(snode->type);
  serializer(snode->_morton);
  serializer(snode->get_snode_tree_id());
}

std::string get_hashed_offline_cache_key_of_snode(SNode *snode) {
  TI_ASSERT(snode);

  BinaryOutputSerializer serializer;
  serializer.initialize();
  {
    std::unordered_set<int> visited;
    get_offline_cache_key_of_snode_impl(snode, serializer, visited);
  }
  serializer.finalize();

  picosha2::hash256_one_by_one hasher;
  hasher.process(serializer.data.begin(), serializer.data.end());
  hasher.finish();

  return picosha2::get_hash_hex_string(hasher);
}

std::string get_hashed_offline_cache_key(CompileConfig *config,
                                         Kernel *kernel) {
  std::string kernel_ast_string;
  if (kernel) {
    std::ostringstream oss;
    gen_offline_cache_key(kernel->program, kernel->ir.get(), &oss);
    kernel_ast_string = oss.str();
  }

  std::vector<std::uint8_t> compile_config_key;
  if (config) {
    compile_config_key = get_offline_cache_key_of_compile_config(config);
  }

  picosha2::hash256_one_by_one hasher;
  hasher.process(compile_config_key.begin(), compile_config_key.end());
  hasher.process(kernel_ast_string.begin(), kernel_ast_string.end());
  hasher.finish();

  auto res = picosha2::get_hash_hex_string(hasher);
  res.insert(res.begin(),
             kernel->autodiff_mode != AutodiffMode::kNone ? 'g' : 'n');
  return res;
}

namespace offline_cache {

constexpr std::size_t offline_cache_key_length = 65;
constexpr std::size_t min_mangled_name_length = offline_cache_key_length + 2;

std::string mangle_name(const std::string &primal_name,
                        const std::string &key) {
  // Result: {primal_name}{key: char[65]}_{(checksum(primal_name)) ^
  // checksum(key)}
  if (key.size() != offline_cache_key_length) {
    return primal_name;
  }
  std::size_t checksum1{0}, checksum2{0};
  for (auto &e : primal_name) {
    checksum1 += std::size_t(e);
  }
  for (auto &e : key) {
    checksum2 += std::size_t(e);
  }
  return fmt::format("{}{}_{}", primal_name, key, checksum1 ^ checksum2);
}

bool try_demangle_name(const std::string &mangled_name,
                       std::string &primal_name,
                       std::string &key) {
  if (mangled_name.size() < min_mangled_name_length) {
    return false;
  }

  std::size_t checksum{0}, checksum1{0}, checksum2{0};
  auto pos = mangled_name.find_last_of('_');
  if (pos == std::string::npos) {
    return false;
  }
  try {
    checksum = std::stoull(mangled_name.substr(pos + 1));
  } catch (const std::exception &) {
    return false;
  }

  std::size_t i = 0, primal_len = pos - offline_cache_key_length;
  for (i = 0; i < primal_len; ++i) {
    checksum1 += (int)mangled_name[i];
  }
  for (; i < pos; ++i) {
    checksum2 += (int)mangled_name[i];
  }
  if ((checksum1 ^ checksum2) != checksum) {
    return false;
  }

  primal_name = mangled_name.substr(0, primal_len);
  key = mangled_name.substr(primal_len, offline_cache_key_length);
  TI_ASSERT(key.size() == offline_cache_key_length);
  TI_ASSERT(primal_name.size() + key.size() == pos);
  return true;
}

}  // namespace offline_cache

}  // namespace lang
}  // namespace taichi
<commit_msg>[bug] Fix incorrect autodiff_mode information in offline cache key (#5737)<commit_after>#include "offline_cache_util.h"

#include "taichi/common/core.h"
#include "taichi/common/serialization.h"
#include "taichi/ir/snode.h"
#include "taichi/ir/transforms.h"
#include "taichi/program/compile_config.h"
#include "taichi/program/kernel.h"

#include "picosha2.h"

#include <vector>

namespace taichi {
namespace lang {

static std::vector<std::uint8_t> get_offline_cache_key_of_compile_config(
    CompileConfig *config) {
  TI_ASSERT(config);
  BinaryOutputSerializer serializer;
  serializer.initialize();
  serializer(config->arch);
  serializer(config->debug);
  serializer(config->cfg_optimization);
  serializer(config->check_out_of_bound);
  serializer(config->opt_level);
  serializer(config->external_optimization_level);
  serializer(config->packed);
  serializer(config->move_loop_invariant_outside_if);
  serializer(config->demote_dense_struct_fors);
  serializer(config->advanced_optimization);
  serializer(config->constant_folding);
  serializer(config->kernel_profiler);
  serializer(config->fast_math);
  serializer(config->flatten_if);
  serializer(config->make_thread_local);
  serializer(config->make_block_local);
  serializer(config->detect_read_only);
  serializer(config->default_fp->to_string());
  serializer(config->default_ip.to_string());
  if (arch_is_cpu(config->arch)) {
    serializer(config->default_cpu_block_dim);
    serializer(config->cpu_max_num_threads);
  } else if (arch_is_gpu(config->arch)) {
    serializer(config->default_gpu_block_dim);
    serializer(config->gpu_max_reg);
    serializer(config->saturating_grid_dim);
    serializer(config->cpu_max_num_threads);
  }
  serializer(config->ad_stack_size);
  serializer(config->default_ad_stack_size);
  serializer(config->random_seed);
  if (config->arch == Arch::cc) {
    serializer(config->cc_compile_cmd);
    serializer(config->cc_link_cmd);
  } else if (config->arch == Arch::opengl) {
    serializer(config->allow_nv_shader_extension);
    serializer(config->use_gles);
  }
  serializer(config->make_mesh_block_local);
  serializer(config->optimize_mesh_reordered_mapping);
  serializer(config->mesh_localize_to_end_mapping);
  serializer(config->mesh_localize_from_end_mapping);
  serializer(config->mesh_localize_all_attr_mappings);
  serializer(config->demote_no_access_mesh_fors);
  serializer(config->experimental_auto_mesh_local);
  serializer(config->auto_mesh_local_default_occupacy);
  serializer.finalize();

  return serializer.data;
}

static void get_offline_cache_key_of_snode_impl(
    SNode *snode,
    BinaryOutputSerializer &serializer,
    std::unordered_set<int> &visited) {
  if (auto iter = visited.find(snode->id); iter != visited.end()) {
    serializer(snode->id);  // Use snode->id as placeholder to identify a snode
    return;
  }

  visited.insert(snode->id);
  for (auto &c : snode->ch) {
    get_offline_cache_key_of_snode_impl(c.get(), serializer, visited);
  }
  for (int i = 0; i < taichi_max_num_indices; ++i) {
    auto &extractor = snode->extractors[i];
    serializer(extractor.num_elements_from_root);
    serializer(extractor.shape);
    serializer(extractor.acc_shape);
    serializer(extractor.num_bits);
    serializer(extractor.acc_offset);
    serializer(extractor.active);
  }
  serializer(snode->index_offsets);
  serializer(snode->num_active_indices);
  serializer(snode->physical_index_position);
  serializer(snode->id);
  serializer(snode->depth);
  serializer(snode->name);
  serializer(snode->num_cells_per_container);
  serializer(snode->total_num_bits);
  serializer(snode->total_bit_start);
  serializer(snode->chunk_size);
  serializer(snode->cell_size_bytes);
  serializer(snode->offset_bytes_in_parent_cell);
  serializer(snode->dt->to_string());
  serializer(snode->has_ambient);
  if (!snode->ambient_val.dt->is_primitive(PrimitiveTypeID::unknown)) {
    serializer(snode->ambient_val.stringify());
  }
  if (snode->grad_info && !snode->grad_info->is_primal()) {
    if (auto *adjoint_snode = snode->grad_info->adjoint_snode()) {
      get_offline_cache_key_of_snode_impl(adjoint_snode, serializer, visited);
    }
    if (auto *dual_snode = snode->grad_info->dual_snode()) {
      get_offline_cache_key_of_snode_impl(dual_snode, serializer, visited);
    }
  }
  if (snode->physical_type) {
    serializer(snode->physical_type->to_string());
  }
  serializer(snode->id_in_bit_struct);
  serializer(snode->is_bit_level);
  serializer(snode->is_path_all_dense);
  serializer(snode->node_type_name);
  serializer(snode->type);
  serializer(snode->_morton);
  serializer(snode->get_snode_tree_id());
}

std::string get_hashed_offline_cache_key_of_snode(SNode *snode) {
  TI_ASSERT(snode);

  BinaryOutputSerializer serializer;
  serializer.initialize();
  {
    std::unordered_set<int> visited;
    get_offline_cache_key_of_snode_impl(snode, serializer, visited);
  }
  serializer.finalize();

  picosha2::hash256_one_by_one hasher;
  hasher.process(serializer.data.begin(), serializer.data.end());
  hasher.finish();

  return picosha2::get_hash_hex_string(hasher);
}

std::string get_hashed_offline_cache_key(CompileConfig *config,
                                         Kernel *kernel) {
  std::string kernel_ast_string;
  if (kernel) {
    std::ostringstream oss;
    gen_offline_cache_key(kernel->program, kernel->ir.get(), &oss);
    kernel_ast_string = oss.str();
  }

  std::vector<std::uint8_t> compile_config_key;
  if (config) {
    compile_config_key = get_offline_cache_key_of_compile_config(config);
  }

  std::string autodiff_mode =
      std::to_string(static_cast<std::size_t>(kernel->autodiff_mode));
  picosha2::hash256_one_by_one hasher;
  hasher.process(compile_config_key.begin(), compile_config_key.end());
  hasher.process(kernel_ast_string.begin(), kernel_ast_string.end());
  hasher.process(autodiff_mode.begin(), autodiff_mode.end());
  hasher.finish();

  auto res = picosha2::get_hash_hex_string(hasher);
  res.insert(res.begin(), 'T');  // The key must start with a letter
  return res;
}

namespace offline_cache {

constexpr std::size_t offline_cache_key_length = 65;
constexpr std::size_t min_mangled_name_length = offline_cache_key_length + 2;

std::string mangle_name(const std::string &primal_name,
                        const std::string &key) {
  // Result: {primal_name}{key: char[65]}_{(checksum(primal_name)) ^
  // checksum(key)}
  if (key.size() != offline_cache_key_length) {
    return primal_name;
  }
  std::size_t checksum1{0}, checksum2{0};
  for (auto &e : primal_name) {
    checksum1 += std::size_t(e);
  }
  for (auto &e : key) {
    checksum2 += std::size_t(e);
  }
  return fmt::format("{}{}_{}", primal_name, key, checksum1 ^ checksum2);
}

bool try_demangle_name(const std::string &mangled_name,
                       std::string &primal_name,
                       std::string &key) {
  if (mangled_name.size() < min_mangled_name_length) {
    return false;
  }

  std::size_t checksum{0}, checksum1{0}, checksum2{0};
  auto pos = mangled_name.find_last_of('_');
  if (pos == std::string::npos) {
    return false;
  }
  try {
    checksum = std::stoull(mangled_name.substr(pos + 1));
  } catch (const std::exception &) {
    return false;
  }

  std::size_t i = 0, primal_len = pos - offline_cache_key_length;
  for (i = 0; i < primal_len; ++i) {
    checksum1 += (int)mangled_name[i];
  }
  for (; i < pos; ++i) {
    checksum2 += (int)mangled_name[i];
  }
  if ((checksum1 ^ checksum2) != checksum) {
    return false;
  }

  primal_name = mangled_name.substr(0, primal_len);
  key = mangled_name.substr(primal_len, offline_cache_key_length);
  TI_ASSERT(key.size() == offline_cache_key_length);
  TI_ASSERT(primal_name.size() + key.size() == pos);
  return true;
}

}  // namespace offline_cache

}  // namespace lang
}  // namespace taichi
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "contentnoteditableindicator.h"
#include "nodemetainfo.h"

#include <QSet>

namespace QmlDesigner {

ContentNotEditableIndicator::ContentNotEditableIndicator(LayerItem *layerItem)
    : m_layerItem(layerItem)
{

}

ContentNotEditableIndicator::ContentNotEditableIndicator()
{
}

ContentNotEditableIndicator::~ContentNotEditableIndicator()
{
    clear();
}

void ContentNotEditableIndicator::clear()
{
    foreach (const EntryPair &entryPair, m_entryList) {
        delete entryPair.second;
        entryPair.first->blurContent(false);
    }

    m_entryList.clear();
}

bool operator ==(const ContentNotEditableIndicator::EntryPair &firstPair, const ContentNotEditableIndicator::EntryPair &secondPair)
{
    return firstPair.first == secondPair.first;
}

void ContentNotEditableIndicator::setItems(const QList<FormEditorItem*> &itemList)
{
    removeEntriesWhichAreNotInTheList(itemList);
    addAddiationEntries(itemList);
}

void ContentNotEditableIndicator::updateItems(const QList<FormEditorItem *> &itemList)
{
    QSet<FormEditorItem*> affectedFormEditorItemItems;
    affectedFormEditorItemItems.unite(itemList.toSet());
    foreach (FormEditorItem *formEditorItem, itemList)
        affectedFormEditorItemItems.unite(formEditorItem->offspringFormEditorItems().toSet());

    foreach (const EntryPair &entryPair, m_entryList) {
         foreach (FormEditorItem *formEditorItem, affectedFormEditorItemItems) {
             if (formEditorItem == entryPair.first) {
                 QRectF boundingRectangleInSceneSpace = formEditorItem->qmlItemNode().instanceSceneTransform().mapRect(formEditorItem->qmlItemNode().instanceBoundingRect());
                 entryPair.second->setRect(boundingRectangleInSceneSpace);
                 entryPair.second->update();
             }
         }
    }
}

void ContentNotEditableIndicator::addAddiationEntries(const QList<FormEditorItem *> &itemList)
{
    foreach (FormEditorItem *formEditorItem, itemList) {
        if (formEditorItem->qmlItemNode().modelNode().metaInfo().isSubclassOf("QtQuick.Loader", -1, -1)) {

            if (!m_entryList.contains(EntryPair(formEditorItem, 0))) {
                QGraphicsRectItem *indicatorShape = new QGraphicsRectItem(m_layerItem);
                QPen linePen;
                linePen.setColor("#a0a0a0");
                indicatorShape->setPen(linePen);
                QRectF boundingRectangleInSceneSpace = formEditorItem->qmlItemNode().instanceSceneTransform().mapRect(formEditorItem->qmlItemNode().instanceBoundingRect());
                indicatorShape->setRect(boundingRectangleInSceneSpace);
                static QBrush brush(QColor(0, 0, 0, 10), Qt::BDiagPattern);
                indicatorShape->setBrush(brush);

                m_entryList.append(EntryPair(formEditorItem, indicatorShape));
            }

        }
    }
}

void ContentNotEditableIndicator::removeEntriesWhichAreNotInTheList(const QList<FormEditorItem *> &itemList)
{
    QMutableListIterator<EntryPair> entryIterator(m_entryList);

    while (entryIterator.hasNext()) {
        EntryPair &entryPair = entryIterator.next();
        if (!itemList.contains(entryPair.first)) {
            delete entryPair.second;
            entryPair.first->blurContent(false);
            entryIterator.remove();
        }
    }
}

} // namespace QmlDesigner
<commit_msg>QmlDesigner: Compile fix<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "contentnoteditableindicator.h"
#include "nodemetainfo.h"

#include <QSet>
#include <QPen>

namespace QmlDesigner {

ContentNotEditableIndicator::ContentNotEditableIndicator(LayerItem *layerItem)
    : m_layerItem(layerItem)
{

}

ContentNotEditableIndicator::ContentNotEditableIndicator()
{
}

ContentNotEditableIndicator::~ContentNotEditableIndicator()
{
    clear();
}

void ContentNotEditableIndicator::clear()
{
    foreach (const EntryPair &entryPair, m_entryList) {
        delete entryPair.second;
        entryPair.first->blurContent(false);
    }

    m_entryList.clear();
}

bool operator ==(const ContentNotEditableIndicator::EntryPair &firstPair, const ContentNotEditableIndicator::EntryPair &secondPair)
{
    return firstPair.first == secondPair.first;
}

void ContentNotEditableIndicator::setItems(const QList<FormEditorItem*> &itemList)
{
    removeEntriesWhichAreNotInTheList(itemList);
    addAddiationEntries(itemList);
}

void ContentNotEditableIndicator::updateItems(const QList<FormEditorItem *> &itemList)
{
    QSet<FormEditorItem*> affectedFormEditorItemItems;
    affectedFormEditorItemItems.unite(itemList.toSet());
    foreach (FormEditorItem *formEditorItem, itemList)
        affectedFormEditorItemItems.unite(formEditorItem->offspringFormEditorItems().toSet());

    foreach (const EntryPair &entryPair, m_entryList) {
         foreach (FormEditorItem *formEditorItem, affectedFormEditorItemItems) {
             if (formEditorItem == entryPair.first) {
                 QRectF boundingRectangleInSceneSpace = formEditorItem->qmlItemNode().instanceSceneTransform().mapRect(formEditorItem->qmlItemNode().instanceBoundingRect());
                 entryPair.second->setRect(boundingRectangleInSceneSpace);
                 entryPair.second->update();
             }
         }
    }
}

void ContentNotEditableIndicator::addAddiationEntries(const QList<FormEditorItem *> &itemList)
{
    foreach (FormEditorItem *formEditorItem, itemList) {
        if (formEditorItem->qmlItemNode().modelNode().metaInfo().isSubclassOf("QtQuick.Loader", -1, -1)) {

            if (!m_entryList.contains(EntryPair(formEditorItem, 0))) {
                QGraphicsRectItem *indicatorShape = new QGraphicsRectItem(m_layerItem);
                QPen linePen;
                linePen.setColor("#a0a0a0");
                indicatorShape->setPen(linePen);
                QRectF boundingRectangleInSceneSpace = formEditorItem->qmlItemNode().instanceSceneTransform().mapRect(formEditorItem->qmlItemNode().instanceBoundingRect());
                indicatorShape->setRect(boundingRectangleInSceneSpace);
                static QBrush brush(QColor(0, 0, 0, 10), Qt::BDiagPattern);
                indicatorShape->setBrush(brush);

                m_entryList.append(EntryPair(formEditorItem, indicatorShape));
            }

        }
    }
}

void ContentNotEditableIndicator::removeEntriesWhichAreNotInTheList(const QList<FormEditorItem *> &itemList)
{
    QMutableListIterator<EntryPair> entryIterator(m_entryList);

    while (entryIterator.hasNext()) {
        EntryPair &entryPair = entryIterator.next();
        if (!itemList.contains(entryPair.first)) {
            delete entryPair.second;
            entryPair.first->blurContent(false);
            entryIterator.remove();
        }
    }
}

} // namespace QmlDesigner
<|endoftext|>


<commit_before>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

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 <string>

#include "flatbuffers/flexbuffers.h"  // from @flatbuffers
#include "mlir/Pass/Pass.h"  // from @llvm-project
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"  // from @llvm-project
#include "tensorflow/compiler/mlir/lite/ir/tfl_ops.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_dialect.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_ops.h"
#include "tensorflow/compiler/mlir/tensorflow/translate/export_tf_dialect_op.h"

namespace mlir {
namespace TF {
namespace {

// The name prefix of Flex ops.
constexpr char kFlexOpNamePrefix[] = "Flex";
constexpr char kDefaultMode[] = "DEFAULT";
constexpr char kLegacyIntegerMode[] = "LEGACY_INTEGER";

// Checks if the operation is allowlisted in the Legacy Integer mode.
bool IsAllowListedOpInLegacyMode(Operation *op) {
  if (llvm::isa<
          // clang-format off
          // go/keep-sorted start
          TF::AbsOp,
          TF::AddOp,
          TF::AddV2Op,
          TF::ArgMaxOp,
          TF::AvgPoolOp,
          TF::BiasAddOp,
          TF::BucketizeOp,
          TF::ConcatV2Op,
          TF::ConstOp,
          TF::Conv2DBackpropInputOp,
          TF::Conv2DOp,
          TF::DepthwiseConv2dNativeOp,
          TF::FakeQuantWithMinMaxVarsOp,
          TF::FakeQuantWithMinMaxVarsPerChannelOp,
          TF::GatherV2Op,
          TF::IdentityOp,
          TF::MatMulOp,
          TF::MaxPoolOp,
          TF::MaximumOp,
          TF::MeanOp,
          TF::MinimumOp,
          TF::MulOp,
          TF::PadOp,
          TF::PadV2Op,
          TF::PartitionedCallOp,
          TF::Relu6Op,
          TF::ReluOp,
          TF::ReshapeOp,
          TF::SoftmaxOp,
          TF::StatefulPartitionedCallOp,
          TF::SubOp,
          TF::TransposeOp
          // go/keep-sorted end
          // clang-format on
          >(op)) {
    return true;
  }
  return false;
}

// Checks if the operation is allowlisted in the Default mode.
bool IsAllowListedOpInDefaultMode(Operation *op) {
  if (llvm::isa<
          // clang-format off
          // go/keep-sorted start
          TF::BiasAddOp,
          TF::ConstOp,
          TF::Conv2DBackpropInputOp,
          TF::Conv2DOp,
          TF::DepthwiseConv2dNativeOp,
          TF::FakeQuantWithMinMaxVarsOp,
          TF::FakeQuantWithMinMaxVarsPerChannelOp,
          TF::IdentityOp,
          TF::MatMulOp,
          TF::PartitionedCallOp,
          TF::Relu6Op,
          TF::ReluOp,
          TF::StatefulPartitionedCallOp
          // go/keep-sorted end
          // clang-format on
          >(op)) {
    return true;
  }
  return false;
}

// Checks if the operation can be fused with bias.
inline bool IsFusibleWithBiasOp(Operation *op) {
  if (llvm::isa<
          // clang-format off
          TF::MatMulOp,
          TF::Conv2DOp,
          TF::DepthwiseConv2dNativeOp,
          TF::Conv2DBackpropInputOp,
          TF::Conv3DOp,
          TF::Conv3DBackpropInputV2Op
          // clang-format on
          >(op)) {
    return true;
  }
  return false;
}

// If the Add op can be fused as bias, converts it to BiasAdd op.
class ConvertAddToBiasAddPattern : public OpRewritePattern<TF::AddV2Op> {
 public:
  using OpRewritePattern<TF::AddV2Op>::OpRewritePattern;

  LogicalResult matchAndRewrite(TF::AddV2Op add_op,
                                PatternRewriter &rewriter) const override {
    // Fusable AddOp must have 1D constant value in the rhs since the BiasAddOp
    // can only accept 1D bias value and only constant value can be fused.
    DenseElementsAttr added_value;
    if (!matchPattern(add_op.y(), m_Constant(&added_value))) return failure();
    if (!IsFusibleWithBiasOp(add_op.x().getDefiningOp())) return failure();
    auto y_type = add_op.y().getType().template dyn_cast<RankedTensorType>();
    if (!y_type || y_type.getRank() != 1) return failure();

    rewriter.replaceOpWithNewOp<TF::BiasAddOp>(add_op, add_op.getType(),
                                               add_op.x(), add_op.y());
    return success();
  }
};

// If the Sub op can be fused as bias, converts it to BiasAdd op.
class ConvertSubToBiasAddPattern : public OpRewritePattern<TF::SubOp> {
 public:
  using OpRewritePattern<TF::SubOp>::OpRewritePattern;

  LogicalResult matchAndRewrite(TF::SubOp sub_op,
                                PatternRewriter &rewriter) const override {
    // Fusable AddOp must have 1D constant value in the rhs since the BiasAddOp
    // can only accept 1D bias value and only constant value can be fused.
    DenseElementsAttr sub_value;
    if (!matchPattern(sub_op.y(), m_Constant(&sub_value))) return failure();
    if (!IsFusibleWithBiasOp(sub_op.x().getDefiningOp())) return failure();
    auto y_type = sub_op.y().getType().template dyn_cast<RankedTensorType>();
    if (!y_type || y_type.getRank() != 1) return failure();

    auto add_value = rewriter.create<TF::NegOp>(sub_op.getLoc(), sub_op.y());
    rewriter.replaceOpWithNewOp<TF::BiasAddOp>(sub_op, sub_op.getType(),
                                               sub_op.x(), add_value);
    return success();
  }
};

// Creates the custom option of the Flex ops.
inline void CreateFlexOpCustomOptions(const std::string &op_name,
                                      const std::string &node_def_str,
                                      std::string &custom_option_buffer) {
  auto flex_builder = absl::make_unique<flexbuffers::Builder>();
  flex_builder->Vector([&]() {
    flex_builder->String(op_name);
    flex_builder->String(node_def_str);
  });
  flex_builder->Finish();
  custom_option_buffer.assign(flex_builder->GetBuffer().begin(),
                              flex_builder->GetBuffer().end());
}

// Creates ElementsAttr for custom option.
inline OpaqueElementsAttr CustomOptionForFlexOp(OpBuilder *builder,
                                                const std::string &content) {
  ShapedType type = RankedTensorType::get(
      {static_cast<int64_t>(content.size())}, builder->getIntegerType(8));
  return OpaqueElementsAttr::get(builder->getContext()->getLoadedDialect("tfl"),
                                 type,
                                 StringRef(content.data(), content.size()));
}

// Fallbacks ops that are not supported by TF Quantization to TFLite Flex ops.
class FallbackToFlexOps : public PassWrapper<FallbackToFlexOps, FunctionPass> {
 public:
  FallbackToFlexOps() {}
  explicit FallbackToFlexOps(const std::string &mode) { mode_ = mode; }
  FallbackToFlexOps(const FallbackToFlexOps &other) { mode_ = other.mode_; }

  void runOnFunction() override;

  StringRef getArgument() const final { return "quant-raise-flex-fallback"; }

  StringRef getDescription() const final {
    return "Fallback TF-Quantization-unsupported ops to TFLite Flex ops.";
  }

  void getDependentDialects(DialectRegistry &registry) const override {
    registry.insert<TFL::TensorFlowLiteDialect>();
  }

 private:
  // The mode of TF Quantization, might indicate different users/devices.
  Option<std::string> mode_{*this, "mode",
                            llvm::cl::desc("The mode of TF Quantization."),
                            llvm::cl::init("")};

  // Checks if the operation is allowlisted in the current mode.
  bool IsAllowListedOp(Operation *op) {
    if (mode_ == kDefaultMode) {
      return IsAllowListedOpInDefaultMode(op);
    } else if (mode_ == kLegacyIntegerMode) {
      return IsAllowListedOpInLegacyMode(op);
    } else {
      mlir::emitError(getFunction().getLoc(), "Unregconized mode: " + mode_);
      signalPassFailure();
      return true;
    }
  }

  // Converts the operation to a TFLite Flex op.
  bool ConvertToFlexOp(Operation *op);
};

bool FallbackToFlexOps::ConvertToFlexOp(Operation *op) {
  tensorflow::StatusOr<std::unique_ptr<tensorflow::NodeDef>> node_def =
      tensorflow::ConvertTFDialectOpToNodeDef(
          op, /*name=*/"", /*ignore_unregistered_attrs=*/true);
  if (!node_def.ok()) {
    op->emitError("Failed to obtain TensorFlow NodeDef: " +
                  node_def.status().ToString());
    return false;
  }
  std::string node_def_str;
  if (!(*node_def)->SerializeToString(&node_def_str)) {
    op->emitError("Failed to serialize tensorflow NodeDef");
    return false;
  }
  std::string op_name = (*node_def)->op();

  OpBuilder builder(op);
  std::string flex_op_name = std::string(kFlexOpNamePrefix) + op_name;
  std::string custom_option_buffer;
  CreateFlexOpCustomOptions(op_name, node_def_str, custom_option_buffer);
  auto flex_op = builder.create<TFL::CustomOp>(
      op->getLoc(), op->getResultTypes(), op->getOperands(), flex_op_name,
      CustomOptionForFlexOp(&builder, custom_option_buffer));
  op->replaceAllUsesWith(flex_op);
  op->erase();
  return true;
}

#include "tensorflow/compiler/mlir/lite/quantization/tensorflow/fallback_to_flex_patterns.inc"

void FallbackToFlexOps::runOnFunction() {
  if (mode_.empty()) return;

  FuncOp func = getFunction();
  MLIRContext *ctx = &getContext();

  // Convert binary ops to BiasAdd ops if possible.
  OwningRewritePatternList patterns(ctx);
  populateWithGenerated(patterns);
  patterns.insert<ConvertAddToBiasAddPattern, ConvertSubToBiasAddPattern>(ctx);
  (void)applyPatternsAndFoldGreedily(func, std::move(patterns));

  // Convert unsupported ops to Flex ops.
  auto tf_dialect = ctx->getLoadedDialect<TF::TensorFlowDialect>();
  func.walk([&](Operation *op) {
    if (op->getDialect() != tf_dialect) return;
    if (IsAllowListedOp(op)) return;
    if (!ConvertToFlexOp(op)) signalPassFailure();
  });
}
}  // namespace

std::unique_ptr<OperationPass<FuncOp>> CreateFallbackToFlexOpsPass(
    const std::string &mode) {
  return std::make_unique<FallbackToFlexOps>(mode);
}

static PassRegistration<FallbackToFlexOps> pass([] {
  return CreateFallbackToFlexOpsPass(/*mode=*/kDefaultMode);
});

}  // namespace TF
}  // namespace mlir
<commit_msg>Split the TF Quantization allowlist into quantizable ops and other allowlisted ops<commit_after>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

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 <string>
#include <utility>

#include "flatbuffers/flexbuffers.h"  // from @flatbuffers
#include "mlir/Pass/Pass.h"  // from @llvm-project
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"  // from @llvm-project
#include "tensorflow/compiler/mlir/lite/ir/tfl_ops.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_dialect.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_ops.h"
#include "tensorflow/compiler/mlir/tensorflow/translate/export_tf_dialect_op.h"

namespace mlir {
namespace TF {
namespace {

// The name prefix of Flex ops.
constexpr char kFlexOpNamePrefix[] = "Flex";
constexpr char kDefaultMode[] = "DEFAULT";
constexpr char kLegacyIntegerMode[] = "LEGACY_INTEGER";

// Checks if the operation is TF FakeQuant ops.
bool IsTfFakeQuantOp(Operation *op) {
  return llvm::isa<
      // clang-format off
      TF::FakeQuantWithMinMaxArgsOp,
      TF::FakeQuantWithMinMaxVarsOp,
      TF::FakeQuantWithMinMaxVarsPerChannelOp
      // clang-format on
      >(op);
}

// Checks if the operation is allowlisted in both modes. These ops are not
// quantizable but is necessary to make the conversion successful.
bool IsAlwaysAllowlistedOp(Operation *op) {
  return llvm::isa<
      // clang-format off
      // go/keep-sorted start
      TF::ConstOp,
      TF::IdentityOp,
      TF::PartitionedCallOp,
      TF::StatefulPartitionedCallOp
      // go/keep-sorted end
      // clang-format on
      >(op);
}

// Checks if the operation is quantizable in the Legacy Integer mode.
bool IsQuantizableOpInLegacyMode(Operation *op) {
  return llvm::isa<
      // clang-format off
      // go/keep-sorted start
      TF::AbsOp,
      TF::AddOp,
      TF::AddV2Op,
      TF::ArgMaxOp,
      TF::AvgPoolOp,
      TF::BiasAddOp,
      TF::BucketizeOp,
      TF::ConcatV2Op,
      TF::Conv2DBackpropInputOp,
      TF::Conv2DOp,
      TF::DepthwiseConv2dNativeOp,
      TF::GatherV2Op,
      TF::MatMulOp,
      TF::MaxPoolOp,
      TF::MaximumOp,
      TF::MeanOp,
      TF::MinimumOp,
      TF::MulOp,
      TF::PadOp,
      TF::PadV2Op,
      TF::Relu6Op,
      TF::ReluOp,
      TF::ReshapeOp,
      TF::SoftmaxOp,
      TF::SubOp,
      TF::TransposeOp
      // go/keep-sorted end
      // clang-format on
      >(op);
}

// Checks if the operation is quantizable in the Default mode.
bool IsQuantizableOpInDefaultMode(Operation *op) {
  return llvm::isa<
      // clang-format off
      // go/keep-sorted start
      TF::BiasAddOp,
      TF::Conv2DBackpropInputOp,
      TF::Conv2DOp,
      TF::DepthwiseConv2dNativeOp,
      TF::MatMulOp,
      TF::Relu6Op,
      TF::ReluOp
      // go/keep-sorted end
      // clang-format on
      >(op);
}

// Checks if the operation can be fused with bias.
inline bool IsFusibleWithBiasOp(Operation *op) {
  return llvm::isa<
      // clang-format off
      TF::MatMulOp,
      TF::Conv2DOp,
      TF::DepthwiseConv2dNativeOp,
      TF::Conv2DBackpropInputOp,
      TF::Conv3DOp,
      TF::Conv3DBackpropInputV2Op
      // clang-format on
      >(op);
}

// If the Add op can be fused as bias, converts it to BiasAdd op.
class ConvertAddToBiasAddPattern : public OpRewritePattern<TF::AddV2Op> {
 public:
  using OpRewritePattern<TF::AddV2Op>::OpRewritePattern;

  LogicalResult matchAndRewrite(TF::AddV2Op add_op,
                                PatternRewriter &rewriter) const override {
    // Fusable AddOp must have 1D constant value in the rhs since the BiasAddOp
    // can only accept 1D bias value and only constant value can be fused.
    DenseElementsAttr added_value;
    if (!matchPattern(add_op.y(), m_Constant(&added_value))) return failure();
    if (!IsFusibleWithBiasOp(add_op.x().getDefiningOp())) return failure();
    auto y_type = add_op.y().getType().template dyn_cast<RankedTensorType>();
    if (!y_type || y_type.getRank() != 1) return failure();

    rewriter.replaceOpWithNewOp<TF::BiasAddOp>(add_op, add_op.getType(),
                                               add_op.x(), add_op.y());
    return success();
  }
};

// If the Sub op can be fused as bias, converts it to BiasAdd op.
class ConvertSubToBiasAddPattern : public OpRewritePattern<TF::SubOp> {
 public:
  using OpRewritePattern<TF::SubOp>::OpRewritePattern;

  LogicalResult matchAndRewrite(TF::SubOp sub_op,
                                PatternRewriter &rewriter) const override {
    // Fusable AddOp must have 1D constant value in the rhs since the BiasAddOp
    // can only accept 1D bias value and only constant value can be fused.
    DenseElementsAttr sub_value;
    if (!matchPattern(sub_op.y(), m_Constant(&sub_value))) return failure();
    if (!IsFusibleWithBiasOp(sub_op.x().getDefiningOp())) return failure();
    auto y_type = sub_op.y().getType().template dyn_cast<RankedTensorType>();
    if (!y_type || y_type.getRank() != 1) return failure();

    auto add_value = rewriter.create<TF::NegOp>(sub_op.getLoc(), sub_op.y());
    rewriter.replaceOpWithNewOp<TF::BiasAddOp>(sub_op, sub_op.getType(),
                                               sub_op.x(), add_value);
    return success();
  }
};

// Creates the custom option of the Flex ops.
inline void CreateFlexOpCustomOptions(const std::string &op_name,
                                      const std::string &node_def_str,
                                      std::string &custom_option_buffer) {
  auto flex_builder = absl::make_unique<flexbuffers::Builder>();
  flex_builder->Vector([&]() {
    flex_builder->String(op_name);
    flex_builder->String(node_def_str);
  });
  flex_builder->Finish();
  custom_option_buffer.assign(flex_builder->GetBuffer().begin(),
                              flex_builder->GetBuffer().end());
}

// Creates ElementsAttr for custom option.
inline OpaqueElementsAttr CustomOptionForFlexOp(OpBuilder *builder,
                                                const std::string &content) {
  ShapedType type = RankedTensorType::get(
      {static_cast<int64_t>(content.size())}, builder->getIntegerType(8));
  return OpaqueElementsAttr::get(builder->getContext()->getLoadedDialect("tfl"),
                                 type,
                                 StringRef(content.data(), content.size()));
}

// Fallbacks ops that are not supported by TF Quantization to TFLite Flex ops.
class FallbackToFlexOps : public PassWrapper<FallbackToFlexOps, FunctionPass> {
 public:
  FallbackToFlexOps() {}
  explicit FallbackToFlexOps(const std::string &mode) { mode_ = mode; }
  FallbackToFlexOps(const FallbackToFlexOps &other) { mode_ = other.mode_; }

  void runOnFunction() override;

  StringRef getArgument() const final { return "quant-raise-flex-fallback"; }

  StringRef getDescription() const final {
    return "Fallback TF-Quantization-unsupported ops to TFLite Flex ops.";
  }

  void getDependentDialects(DialectRegistry &registry) const override {
    registry.insert<TFL::TensorFlowLiteDialect>();
  }

 private:
  // The mode of TF Quantization, might indicate different users/devices.
  Option<std::string> mode_{*this, "mode",
                            llvm::cl::desc("The mode of TF Quantization."),
                            llvm::cl::init("")};

  // Checks if the operation is allowlisted in the current mode.
  bool IsAllowListedOp(Operation *op) {
    if (IsAlwaysAllowlistedOp(op) || IsTfFakeQuantOp(op)) {
      return true;
    } else if (mode_ == kDefaultMode) {
      return IsQuantizableOpInDefaultMode(op);
    } else if (mode_ == kLegacyIntegerMode) {
      return IsQuantizableOpInLegacyMode(op);
    } else {
      mlir::emitError(getFunction().getLoc(), "Unregconized mode: " + mode_);
      signalPassFailure();
      return true;
    }
  }

  // Converts the operation to a TFLite Flex op.
  bool ConvertToFlexOp(Operation *op);
};

bool FallbackToFlexOps::ConvertToFlexOp(Operation *op) {
  tensorflow::StatusOr<std::unique_ptr<tensorflow::NodeDef>> node_def =
      tensorflow::ConvertTFDialectOpToNodeDef(
          op, /*name=*/"", /*ignore_unregistered_attrs=*/true);
  if (!node_def.ok()) {
    op->emitError("Failed to obtain TensorFlow NodeDef: " +
                  node_def.status().ToString());
    return false;
  }
  std::string node_def_str;
  if (!(*node_def)->SerializeToString(&node_def_str)) {
    op->emitError("Failed to serialize tensorflow NodeDef");
    return false;
  }
  std::string op_name = (*node_def)->op();

  OpBuilder builder(op);
  std::string flex_op_name = std::string(kFlexOpNamePrefix) + op_name;
  std::string custom_option_buffer;
  CreateFlexOpCustomOptions(op_name, node_def_str, custom_option_buffer);
  auto flex_op = builder.create<TFL::CustomOp>(
      op->getLoc(), op->getResultTypes(), op->getOperands(), flex_op_name,
      CustomOptionForFlexOp(&builder, custom_option_buffer));
  op->replaceAllUsesWith(flex_op);
  op->erase();
  return true;
}

#include "tensorflow/compiler/mlir/lite/quantization/tensorflow/fallback_to_flex_patterns.inc"

void FallbackToFlexOps::runOnFunction() {
  if (mode_.empty()) return;

  FuncOp func = getFunction();
  MLIRContext *ctx = &getContext();

  // Convert binary ops to BiasAdd ops if possible.
  OwningRewritePatternList patterns(ctx);
  populateWithGenerated(patterns);
  patterns.insert<ConvertAddToBiasAddPattern, ConvertSubToBiasAddPattern>(ctx);
  (void)applyPatternsAndFoldGreedily(func, std::move(patterns));

  // Convert unsupported ops to Flex ops.
  auto tf_dialect = ctx->getLoadedDialect<TF::TensorFlowDialect>();
  func.walk([&](Operation *op) {
    if (op->getDialect() != tf_dialect) return;
    if (IsAllowListedOp(op)) return;
    if (!ConvertToFlexOp(op)) signalPassFailure();
  });
}
}  // namespace

std::unique_ptr<OperationPass<FuncOp>> CreateFallbackToFlexOpsPass(
    const std::string &mode) {
  return std::make_unique<FallbackToFlexOps>(mode);
}

static PassRegistration<FallbackToFlexOps> pass([] {
  return CreateFallbackToFlexOpsPass(/*mode=*/kDefaultMode);
});

}  // namespace TF
}  // namespace mlir
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: SlsQueueProcessor.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: kz $ $Date: 2006-12-12 18:19:19 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"

#include "SlsQueueProcessor.hxx"
#include "SlsCacheConfiguration.hxx"

namespace sd { namespace slidesorter { namespace cache {

//===== QueueProcessorBase  ===================================================

QueueProcessorBase::QueueProcessorBase (void)
    : mnTimeBetweenHighPriorityRequests (10/*ms*/),
      mnTimeBetweenLowPriorityRequests (100/*ms*/),
      mnTimeBetweenRequestsWhenNotIdle (1000/*ms*/)
{
    // Look into the configuration if there for overriding values.
    ::com::sun::star::uno::Any aTimeBetweenReqeusts;
    aTimeBetweenReqeusts = CacheConfiguration::Instance()->GetValue(
        ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TimeBetweenHighPriorityRequests")));
    if (aTimeBetweenReqeusts.has<sal_Int32>())
        aTimeBetweenReqeusts >>= mnTimeBetweenHighPriorityRequests;

    aTimeBetweenReqeusts = CacheConfiguration::Instance()->GetValue(
        ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TimeBetweenLowPriorityRequests")));
    if (aTimeBetweenReqeusts.has<sal_Int32>())
        aTimeBetweenReqeusts >>= mnTimeBetweenLowPriorityRequests;

    aTimeBetweenReqeusts = CacheConfiguration::Instance()->GetValue(
        ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TimeBetweenRequestsDuringShow")));
    if (aTimeBetweenReqeusts.has<sal_Int32>())
        aTimeBetweenReqeusts >>= mnTimeBetweenRequestsWhenNotIdle;

    maTimer.SetTimeoutHdl (LINK(this,QueueProcessorBase,ProcessRequestHdl));
    maTimer.SetTimeout (mnTimeBetweenHighPriorityRequests);
}

QueueProcessorBase::~QueueProcessorBase()
{
}

void QueueProcessorBase::Start (int nPriorityClass)
{
    if ( ! maTimer.IsActive())
    {
        if (nPriorityClass == 0)
            maTimer.SetTimeout (mnTimeBetweenHighPriorityRequests);
        else
            maTimer.SetTimeout (mnTimeBetweenLowPriorityRequests);
        maTimer.Start();
    }
}

void QueueProcessorBase::Stop (void)
{
    if (maTimer.IsActive())
        maTimer.Stop();
}

IMPL_LINK(QueueProcessorBase, ProcessRequestHdl, Timer*, EMPTYARG)
{
    ProcessRequest();
    return 1;
}

} } } // end of namespace ::sd::slidesorter::cache
<commit_msg>INTEGRATION: CWS presenterview (1.8.54); FILE MERGED 2008/02/26 12:17:38 af 1.8.54.1: #i18486# Dropped the use of templates for implementing cache classes.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: SlsQueueProcessor.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: kz $ $Date: 2008-04-03 14:20:19 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include "precompiled_sd.hxx"

#include "SlsQueueProcessor.hxx"
#include "SlsCacheConfiguration.hxx"
#include "SlsRequestQueue.hxx"
#include "SlsIdleDetector.hxx"

namespace sd { namespace slidesorter { namespace cache {

//=====  QueueProcessor  ======================================================

QueueProcessor::QueueProcessor (
    RequestQueue& rQueue,
    const ::boost::shared_ptr<BitmapCache>& rpCache,
    const Size& rPreviewSize,
    const SharedCacheContext& rpCacheContext)
    : maMutex(),
      maTimer(),
      mnTimeBetweenHighPriorityRequests (10/*ms*/),
      mnTimeBetweenLowPriorityRequests (100/*ms*/),
      mnTimeBetweenRequestsWhenNotIdle (1000/*ms*/),
      maPreviewSize(rPreviewSize),
      mpCacheContext(rpCacheContext),
      mrQueue(rQueue),
      mpCache(rpCache),
      maBitmapFactory(),
      mbIsPaused(false)
{
    // Look into the configuration if there for overriding values.
    ::com::sun::star::uno::Any aTimeBetweenReqeusts;
    aTimeBetweenReqeusts = CacheConfiguration::Instance()->GetValue(
        ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TimeBetweenHighPriorityRequests")));
    if (aTimeBetweenReqeusts.has<sal_Int32>())
        aTimeBetweenReqeusts >>= mnTimeBetweenHighPriorityRequests;

    aTimeBetweenReqeusts = CacheConfiguration::Instance()->GetValue(
        ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TimeBetweenLowPriorityRequests")));
    if (aTimeBetweenReqeusts.has<sal_Int32>())
        aTimeBetweenReqeusts >>= mnTimeBetweenLowPriorityRequests;

    aTimeBetweenReqeusts = CacheConfiguration::Instance()->GetValue(
        ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TimeBetweenRequestsDuringShow")));
    if (aTimeBetweenReqeusts.has<sal_Int32>())
        aTimeBetweenReqeusts >>= mnTimeBetweenRequestsWhenNotIdle;

    maTimer.SetTimeoutHdl (LINK(this,QueueProcessor,ProcessRequestHdl));
    maTimer.SetTimeout (mnTimeBetweenHighPriorityRequests);
}

QueueProcessor::~QueueProcessor (void)
{
}

void QueueProcessor::Start (int nPriorityClass)
{
    if (mbIsPaused)
        return;
    if ( ! maTimer.IsActive())
    {
        if (nPriorityClass == 0)
            maTimer.SetTimeout (mnTimeBetweenHighPriorityRequests);
        else
            maTimer.SetTimeout (mnTimeBetweenLowPriorityRequests);
        maTimer.Start();
    }
}

void QueueProcessor::Stop (void)
{
    if (maTimer.IsActive())
        maTimer.Stop();
}

void QueueProcessor::Pause (void)
{
    mbIsPaused = true;
}

void QueueProcessor::Resume (void)
{
    mbIsPaused = false;
    if ( ! mrQueue.IsEmpty())
        Start(mrQueue.GetFrontPriorityClass());
}

void QueueProcessor::Terminate (void)
{
}

void QueueProcessor::SetPreviewSize (const Size& rPreviewSize)
{
    maPreviewSize = rPreviewSize;
}

IMPL_LINK(QueueProcessor, ProcessRequestHdl, Timer*, EMPTYARG)
{
    ProcessRequests();
    return 1;
}

void QueueProcessor::ProcessRequests (void)
{
    OSL_ASSERT(mpCacheContext.get()!=NULL);

    while ( ! mrQueue.IsEmpty() && ! mbIsPaused)
    {
        if ( ! mpCacheContext->IsIdle())
            break;

        CacheKey aKey = NULL;
        RequestPriorityClass ePriorityClass (NOT_VISIBLE);
        {
            ::osl::MutexGuard aGuard (mrQueue.GetMutex());

            if ( ! mrQueue.IsEmpty())
            {
                // Get the request with the highest priority from the queue.
                ePriorityClass = mrQueue.GetFrontPriorityClass();
                aKey = mrQueue.GetFront();
                mrQueue.PopFront();
            }
        }

        if (aKey != NULL)
            ProcessOneRequest(aKey, ePriorityClass);

        // Requests of lower priority are processed one at a time.
        {
            ::osl::MutexGuard aGuard (mrQueue.GetMutex());
            if ( ! mrQueue.IsEmpty())
                if (mrQueue.GetFrontPriorityClass() > 0)
                    break;
        }
    }

    // Schedule the processing of the next element(s).
    {
        ::osl::MutexGuard aGuard (mrQueue.GetMutex());
        if ( ! mrQueue.IsEmpty())
            /*
            if (bIsShowingFullScreenShow)
                Start(mnTimeBetweenRequestsWhenNotIdle);
            else
            */
            Start(mrQueue.GetFrontPriorityClass());
    }
}

void QueueProcessor::ProcessOneRequest (
    CacheKey aKey,
    const RequestPriorityClass ePriorityClass)
{
    const SdrPage* pPage = mpCacheContext->GetPage(aKey);
    SSCD_SET_STATUS(pPage,RENDERING);

#ifdef VERBOSE
    OSL_TRACE ("processing request for page %d with priority class %d",
        (pPage->GetPageNum()-1)/2,
        ePriorityClass);
#endif
    try
    {
        ::osl::MutexGuard aGuard (maMutex);
        // Create a new preview bitmap and store it in the cache.
        if (mpCache.get() != NULL)
        {
            const SdPage* pSdPage = dynamic_cast<const SdPage*>(pPage);
            if (pSdPage != NULL)
            {
                const ::boost::shared_ptr<BitmapEx> pPreview (
                    maBitmapFactory.CreateBitmap(*pSdPage, maPreviewSize));
                mpCache->SetBitmap (
                    pPage,
                    pPreview,
                    ePriorityClass!=NOT_VISIBLE);

                // Initiate a repaint of the new preview.
                mpCacheContext->NotifyPreviewCreation(aKey, pPreview);

                SSCD_SET_STATUS(pPage,NONE);
            }
        }
    }
    catch (::com::sun::star::uno::RuntimeException aException)
    {
        OSL_ASSERT("RuntimeException caught in QueueProcessor");
        (void) aException;
    }
    catch (::com::sun::star::uno::Exception aException)
    {
        OSL_ASSERT("Exception caught in QueueProcessor");
        (void) aException;
    }
}

void QueueProcessor::RemoveRequest (CacheKey aKey)
{
    (void)aKey;
    // See the method declaration above for an explanation why this makes sense.
    ::osl::MutexGuard aGuard (maMutex);
}

void QueueProcessor::SetBitmapCache (
    const ::boost::shared_ptr<BitmapCache>& rpCache)
{
    mpCache = rpCache;
}

} } } // end of namespace ::sd::slidesorter::cache
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * 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 <string.h>

#include <grpc/support/log.h>

#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "test/core/util/test_config.h"

static void test_create(void) {
  grpc_core::ExecCtx exec_ctx;

  grpc_arg arg_int;
  grpc_arg arg_string;
  grpc_arg to_add[2];
  grpc_channel_args* ch_args;

  arg_int.key = const_cast<char*>("int_arg");
  arg_int.type = GRPC_ARG_INTEGER;
  arg_int.value.integer = 123;

  arg_string.key = const_cast<char*>("str key");
  arg_string.type = GRPC_ARG_STRING;
  arg_string.value.string = const_cast<char*>("str value");

  to_add[0] = arg_int;
  to_add[1] = arg_string;
  ch_args = grpc_channel_args_copy_and_add(nullptr, to_add, 2);

  GPR_ASSERT(ch_args->num_args == 2);
  GPR_ASSERT(strcmp(ch_args->args[0].key, arg_int.key) == 0);
  GPR_ASSERT(ch_args->args[0].type == arg_int.type);
  GPR_ASSERT(ch_args->args[0].value.integer == arg_int.value.integer);

  GPR_ASSERT(strcmp(ch_args->args[1].key, arg_string.key) == 0);
  GPR_ASSERT(ch_args->args[1].type == arg_string.type);
  GPR_ASSERT(strcmp(ch_args->args[1].value.string, arg_string.value.string) ==
             0);

  grpc_channel_args_destroy(ch_args);
}

static void test_set_compression_algorithm(void) {
  grpc_core::ExecCtx exec_ctx;
  grpc_channel_args* ch_args;

  ch_args =
      grpc_channel_args_set_compression_algorithm(nullptr, GRPC_COMPRESS_GZIP);
  GPR_ASSERT(ch_args->num_args == 1);
  GPR_ASSERT(strcmp(ch_args->args[0].key,
                    GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM) == 0);
  GPR_ASSERT(ch_args->args[0].type == GRPC_ARG_INTEGER);

  grpc_channel_args_destroy(ch_args);
}

static void test_compression_algorithm_states(void) {
  grpc_core::ExecCtx exec_ctx;
  grpc_channel_args *ch_args, *ch_args_wo_gzip, *ch_args_wo_gzip_deflate,
      *ch_args_wo_gzip_deflate_gzip;
  unsigned states_bitset;
  size_t i;

  ch_args = grpc_channel_args_copy_and_add(nullptr, nullptr, 0);
  /* by default, all enabled */
  states_bitset = static_cast<unsigned>(
      grpc_channel_args_compression_algorithm_get_states(ch_args));

  for (i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) {
    GPR_ASSERT(GPR_BITGET(states_bitset, i));
  }

  /* disable gzip and deflate and stream/gzip */
  ch_args_wo_gzip = grpc_channel_args_compression_algorithm_set_state(
      &ch_args, GRPC_COMPRESS_GZIP, 0);
  GPR_ASSERT(ch_args == ch_args_wo_gzip);
  ch_args_wo_gzip_deflate = grpc_channel_args_compression_algorithm_set_state(
      &ch_args_wo_gzip, GRPC_COMPRESS_DEFLATE, 0);
  GPR_ASSERT(ch_args_wo_gzip == ch_args_wo_gzip_deflate);
  ch_args_wo_gzip_deflate_gzip =
      grpc_channel_args_compression_algorithm_set_state(
          &ch_args_wo_gzip_deflate, GRPC_COMPRESS_STREAM_GZIP, 0);
  GPR_ASSERT(ch_args_wo_gzip_deflate == ch_args_wo_gzip_deflate_gzip);

  states_bitset =
      static_cast<unsigned>(grpc_channel_args_compression_algorithm_get_states(
          ch_args_wo_gzip_deflate));
  for (i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) {
    if (i == GRPC_COMPRESS_GZIP || i == GRPC_COMPRESS_DEFLATE ||
        i == GRPC_COMPRESS_STREAM_GZIP) {
      GPR_ASSERT(GPR_BITGET(states_bitset, i) == 0);
    } else {
      GPR_ASSERT(GPR_BITGET(states_bitset, i) != 0);
    }
  }

  /* re-enabled gzip and stream/gzip only */
  ch_args_wo_gzip = grpc_channel_args_compression_algorithm_set_state(
      &ch_args_wo_gzip_deflate_gzip, GRPC_COMPRESS_GZIP, 1);
  ch_args_wo_gzip = grpc_channel_args_compression_algorithm_set_state(
      &ch_args_wo_gzip, GRPC_COMPRESS_STREAM_GZIP, 1);
  GPR_ASSERT(ch_args_wo_gzip == ch_args_wo_gzip_deflate_gzip);

  states_bitset = static_cast<unsigned>(
      grpc_channel_args_compression_algorithm_get_states(ch_args_wo_gzip));
  for (i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) {
    if (i == GRPC_COMPRESS_DEFLATE) {
      GPR_ASSERT(GPR_BITGET(states_bitset, i) == 0);
    } else {
      GPR_ASSERT(GPR_BITGET(states_bitset, i) != 0);
    }
  }

  grpc_channel_args_destroy(ch_args);
}

static void test_set_socket_mutator(void) {
  grpc_channel_args* ch_args;
  grpc_socket_mutator mutator;
  grpc_socket_mutator_init(&mutator, nullptr);

  ch_args = grpc_channel_args_set_socket_mutator(nullptr, &mutator);
  GPR_ASSERT(ch_args->num_args == 1);
  GPR_ASSERT(strcmp(ch_args->args[0].key, GRPC_ARG_SOCKET_MUTATOR) == 0);
  GPR_ASSERT(ch_args->args[0].type == GRPC_ARG_POINTER);

  {
    grpc_core::ExecCtx exec_ctx;
    grpc_channel_args_destroy(ch_args);
  }
}

int main(int argc, char** argv) {
  grpc_test_init(argc, argv);
  grpc_init();
  test_create();
  test_set_compression_algorithm();
  test_compression_algorithm_states();
  test_set_socket_mutator();
  grpc_shutdown();
  return 0;
}
<commit_msg>Add channel arg test for channel/server creation<commit_after>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * 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 <string.h>

#include <grpc/support/log.h>

#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "test/core/util/test_config.h"

static void test_create(void) {
  grpc_core::ExecCtx exec_ctx;

  grpc_arg arg_int;
  grpc_arg arg_string;
  grpc_arg to_add[2];
  grpc_channel_args* ch_args;

  arg_int.key = const_cast<char*>("int_arg");
  arg_int.type = GRPC_ARG_INTEGER;
  arg_int.value.integer = 123;

  arg_string.key = const_cast<char*>("str key");
  arg_string.type = GRPC_ARG_STRING;
  arg_string.value.string = const_cast<char*>("str value");

  to_add[0] = arg_int;
  to_add[1] = arg_string;
  ch_args = grpc_channel_args_copy_and_add(nullptr, to_add, 2);

  GPR_ASSERT(ch_args->num_args == 2);
  GPR_ASSERT(strcmp(ch_args->args[0].key, arg_int.key) == 0);
  GPR_ASSERT(ch_args->args[0].type == arg_int.type);
  GPR_ASSERT(ch_args->args[0].value.integer == arg_int.value.integer);

  GPR_ASSERT(strcmp(ch_args->args[1].key, arg_string.key) == 0);
  GPR_ASSERT(ch_args->args[1].type == arg_string.type);
  GPR_ASSERT(strcmp(ch_args->args[1].value.string, arg_string.value.string) ==
             0);

  grpc_channel_args_destroy(ch_args);
}

static void test_set_compression_algorithm(void) {
  grpc_core::ExecCtx exec_ctx;
  grpc_channel_args* ch_args;

  ch_args =
      grpc_channel_args_set_compression_algorithm(nullptr, GRPC_COMPRESS_GZIP);
  GPR_ASSERT(ch_args->num_args == 1);
  GPR_ASSERT(strcmp(ch_args->args[0].key,
                    GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM) == 0);
  GPR_ASSERT(ch_args->args[0].type == GRPC_ARG_INTEGER);

  grpc_channel_args_destroy(ch_args);
}

static void test_compression_algorithm_states(void) {
  grpc_core::ExecCtx exec_ctx;
  grpc_channel_args *ch_args, *ch_args_wo_gzip, *ch_args_wo_gzip_deflate,
      *ch_args_wo_gzip_deflate_gzip;
  unsigned states_bitset;
  size_t i;

  ch_args = grpc_channel_args_copy_and_add(nullptr, nullptr, 0);
  /* by default, all enabled */
  states_bitset = static_cast<unsigned>(
      grpc_channel_args_compression_algorithm_get_states(ch_args));

  for (i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) {
    GPR_ASSERT(GPR_BITGET(states_bitset, i));
  }

  /* disable gzip and deflate and stream/gzip */
  ch_args_wo_gzip = grpc_channel_args_compression_algorithm_set_state(
      &ch_args, GRPC_COMPRESS_GZIP, 0);
  GPR_ASSERT(ch_args == ch_args_wo_gzip);
  ch_args_wo_gzip_deflate = grpc_channel_args_compression_algorithm_set_state(
      &ch_args_wo_gzip, GRPC_COMPRESS_DEFLATE, 0);
  GPR_ASSERT(ch_args_wo_gzip == ch_args_wo_gzip_deflate);
  ch_args_wo_gzip_deflate_gzip =
      grpc_channel_args_compression_algorithm_set_state(
          &ch_args_wo_gzip_deflate, GRPC_COMPRESS_STREAM_GZIP, 0);
  GPR_ASSERT(ch_args_wo_gzip_deflate == ch_args_wo_gzip_deflate_gzip);

  states_bitset =
      static_cast<unsigned>(grpc_channel_args_compression_algorithm_get_states(
          ch_args_wo_gzip_deflate));
  for (i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) {
    if (i == GRPC_COMPRESS_GZIP || i == GRPC_COMPRESS_DEFLATE ||
        i == GRPC_COMPRESS_STREAM_GZIP) {
      GPR_ASSERT(GPR_BITGET(states_bitset, i) == 0);
    } else {
      GPR_ASSERT(GPR_BITGET(states_bitset, i) != 0);
    }
  }

  /* re-enabled gzip and stream/gzip only */
  ch_args_wo_gzip = grpc_channel_args_compression_algorithm_set_state(
      &ch_args_wo_gzip_deflate_gzip, GRPC_COMPRESS_GZIP, 1);
  ch_args_wo_gzip = grpc_channel_args_compression_algorithm_set_state(
      &ch_args_wo_gzip, GRPC_COMPRESS_STREAM_GZIP, 1);
  GPR_ASSERT(ch_args_wo_gzip == ch_args_wo_gzip_deflate_gzip);

  states_bitset = static_cast<unsigned>(
      grpc_channel_args_compression_algorithm_get_states(ch_args_wo_gzip));
  for (i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) {
    if (i == GRPC_COMPRESS_DEFLATE) {
      GPR_ASSERT(GPR_BITGET(states_bitset, i) == 0);
    } else {
      GPR_ASSERT(GPR_BITGET(states_bitset, i) != 0);
    }
  }

  grpc_channel_args_destroy(ch_args);
}

static void test_set_socket_mutator(void) {
  grpc_channel_args* ch_args;
  grpc_socket_mutator mutator;
  grpc_socket_mutator_init(&mutator, nullptr);

  ch_args = grpc_channel_args_set_socket_mutator(nullptr, &mutator);
  GPR_ASSERT(ch_args->num_args == 1);
  GPR_ASSERT(strcmp(ch_args->args[0].key, GRPC_ARG_SOCKET_MUTATOR) == 0);
  GPR_ASSERT(ch_args->args[0].type == GRPC_ARG_POINTER);

  {
    grpc_core::ExecCtx exec_ctx;
    grpc_channel_args_destroy(ch_args);
  }
}

struct fake_class {
  int foo;
};

static void* fake_pointer_arg_copy(void* arg) {
  fake_class* fc = static_cast<fake_class*>(arg);
  fake_class* new_fc = static_cast<fake_class*>(gpr_malloc(sizeof(fake_class)));
  new_fc->foo = fc->foo;
  return new_fc;
}

static void fake_pointer_arg_destroy(void* arg) {
  fake_class* fc = static_cast<fake_class*>(arg);
  gpr_free(fc);
}

static int fake_pointer_cmp(void* a, void* b) { return GPR_ICMP(a, b); }

static const grpc_arg_pointer_vtable fake_pointer_arg_vtable = {
    fake_pointer_arg_copy, fake_pointer_arg_destroy, fake_pointer_cmp};

static void test_channel_create_with_args(void) {
  grpc_arg client_a[3];

  // adds integer arg
  client_a[0].type = GRPC_ARG_INTEGER;
  client_a[0].key = const_cast<char*>("arg_int");
  client_a[0].value.integer = 0;

  // adds const str arg
  client_a[1].type = GRPC_ARG_STRING;
  client_a[1].key = const_cast<char*>("arg_str");
  client_a[1].value.string = const_cast<char*>("arg_str_val");

  // allocated and adds custom pointer arg
  fake_class* fc = static_cast<fake_class*>(gpr_malloc(sizeof(fake_class)));
  fc->foo = 42;
  client_a[2].type = GRPC_ARG_POINTER;
  client_a[2].key = const_cast<char*>("arg_pointer");
  client_a[2].value.pointer.vtable = &fake_pointer_arg_vtable;
  client_a[2].value.pointer.p = fc;

  // creates channel
  grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
  grpc_channel* c =
      grpc_insecure_channel_create("fake_target", &client_args, nullptr);
  // user is can free the memory they allocated here
  gpr_free(fc);
  grpc_channel_destroy(c);
}

static void test_server_create_with_args(void) {
  grpc_arg server_a[3];

  // adds integer arg
  server_a[0].type = GRPC_ARG_INTEGER;
  server_a[0].key = const_cast<char*>("arg_int");
  server_a[0].value.integer = 0;

  // adds const str arg
  server_a[1].type = GRPC_ARG_STRING;
  server_a[1].key = const_cast<char*>("arg_str");
  server_a[1].value.string = const_cast<char*>("arg_str_val");

  // allocated and adds custom pointer arg
  fake_class* fc = static_cast<fake_class*>(gpr_malloc(sizeof(fake_class)));
  fc->foo = 42;
  server_a[2].type = GRPC_ARG_POINTER;
  server_a[2].key = const_cast<char*>("arg_pointer");
  server_a[2].value.pointer.vtable = &fake_pointer_arg_vtable;
  server_a[2].value.pointer.p = fc;

  // creates server
  grpc_channel_args server_args = {GPR_ARRAY_SIZE(server_a), server_a};
  grpc_server* s = grpc_server_create(&server_args, nullptr);
  // user is can free the memory they allocated here
  gpr_free(fc);
  grpc_server_destroy(s);
}

int main(int argc, char** argv) {
  grpc_test_init(argc, argv);
  grpc_init();
  test_create();
  test_set_compression_algorithm();
  test_compression_algorithm_states();
  test_set_socket_mutator();
  test_channel_create_with_args();
  test_server_create_with_args();
  grpc_shutdown();
  return 0;
}
<|endoftext|>