<commit_before>/*
 *  Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable.
 *
 *  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.
 */

/**
 * @author Li-Gang Wang, 2006/11/15
 */

#include "finalizer_thread.h"
#include "ref_enqueue_thread.h"
#include "finalize.h"
#include "vm_threads.h"
#include "init.h"
#include "open/jthread.h"
#include "jni_direct.h"
#include "jni_utils.h"
#include "slot.h"

static Boolean native_fin_thread_flag = FALSE;
static Fin_Thread_Info *fin_thread_info = NULL;
unsigned int cpu_num_bits;

static uint32 atomic_inc32(volatile apr_uint32_t *mem)
{  return (uint32)apr_atomic_inc32(mem); }

static uint32 atomic_dec32(volatile apr_uint32_t *mem)
{  return (uint32)apr_atomic_dec32(mem); }

Boolean get_native_finalizer_thread_flag()
{  return native_fin_thread_flag; }

void set_native_finalizer_thread_flag(Boolean flag)
{  native_fin_thread_flag = flag; }

Boolean get_finalizer_shutdown_flag()
{  return fin_thread_info->shutdown; }

Boolean get_finalizer_on_exit_flag()
{  return fin_thread_info->on_exit; }

static unsigned int coarse_log(unsigned int num)
{
    unsigned int i = sizeof(unsigned int) << 3;
    unsigned int comp = 1 << (i-1);
    while(i--){
        if(num & comp)
            return i;
        num = num << 1;
    }
    return 0;
}

static IDATA finalizer_thread_func(void **args);
static void wait_fin_threads_attached(void);

void finalizer_threads_init(JavaVM *java_vm)
{
    if(!native_fin_thread_flag)
        return;

    fin_thread_info = (Fin_Thread_Info *)STD_MALLOC(sizeof(Fin_Thread_Info));
    fin_thread_info->thread_num = port_CPUs_number();
    cpu_num_bits = coarse_log(fin_thread_info->thread_num);
    fin_thread_info->working_thread_num = 0;
    fin_thread_info->end_waiting_num = 0;
    fin_thread_info->shutdown = FALSE;
    fin_thread_info->on_exit = FALSE;

    IDATA status = hysem_create(&fin_thread_info->pending_sem, 0, fin_thread_info->thread_num);
    assert(status == TM_ERROR_NONE);

    status = hycond_create(&fin_thread_info->end_cond);
    assert(status == TM_ERROR_NONE);
    status = hymutex_create(&fin_thread_info->end_mutex, TM_MUTEX_DEFAULT);
    assert(status == TM_ERROR_NONE);

    status = hycond_create(&fin_thread_info->mutator_block_cond);
    assert(status == TM_ERROR_NONE);
    status = hymutex_create(&fin_thread_info->mutator_block_mutex, TM_MUTEX_DEFAULT);
    assert(status == TM_ERROR_NONE);

    fin_thread_info->thread_ids = (hythread_t *)STD_MALLOC(sizeof(hythread_t) * fin_thread_info->thread_num);
    fin_thread_info->thread_attached_num = 0;

    for(unsigned int i = 0; i < fin_thread_info->thread_num; i++){
        void **args = (void **)STD_MALLOC(sizeof(void *) * 2);
        args[0] = (void *)java_vm;
        args[1] = (void *)(UDATA)(i + 1);
        fin_thread_info->thread_ids[i] = NULL;
        status = hythread_create(&fin_thread_info->thread_ids[i], 0, FINALIZER_THREAD_PRIORITY, 0, (hythread_entrypoint_t)finalizer_thread_func, args);
        assert(status == TM_ERROR_NONE);
    }

    wait_fin_threads_attached();
}

void finalizer_shutdown(Boolean start_finalization_on_exit)
{
    if(start_finalization_on_exit){
        tmn_suspend_disable();
        gc_force_gc();
        tmn_suspend_enable();
        activate_finalizer_threads(TRUE);
        tmn_suspend_disable();
        gc_finalize_on_exit();
        tmn_suspend_enable();
        fin_thread_info->on_exit = TRUE;
        activate_finalizer_threads(TRUE);
    }
    fin_thread_info->shutdown = TRUE;
    ref_enqueue_shutdown();
    activate_finalizer_threads(TRUE);
}

static void inc_fin_thread_num(void)
{ atomic_inc32(&fin_thread_info->thread_attached_num); }

static void dec_fin_thread_num(void)
{ atomic_dec32(&fin_thread_info->thread_attached_num); }

static void wait_fin_threads_attached(void)
{ while(fin_thread_info->thread_attached_num < fin_thread_info->thread_num); }

void wait_native_fin_threads_detached(void)
{
    hymutex_lock(&fin_thread_info->end_mutex);
    while(fin_thread_info->thread_attached_num){
        atomic_inc32(&fin_thread_info->end_waiting_num);
        IDATA status = hycond_wait_timed(&fin_thread_info->end_cond, &fin_thread_info->end_mutex, (I_64)1000, 0);
        atomic_dec32(&fin_thread_info->end_waiting_num);
        if(status != TM_ERROR_NONE) break;
    }
    hymutex_unlock(&fin_thread_info->end_mutex);
}

/* Restrict waiting time; Unit: msec */
static unsigned int restrict_wait_time(unsigned int wait_time, unsigned int max_time)
{
    if(!wait_time) return 1;
    if(wait_time > max_time) return max_time;
    return wait_time;
}

static void wait_finalization_end(void)
{
    hymutex_lock(&fin_thread_info->end_mutex);
    unsigned int fin_obj_num = vm_get_finalizable_objects_quantity();
    while(fin_thread_info->working_thread_num || fin_obj_num){
        unsigned int wait_time = restrict_wait_time(fin_obj_num + 1000, FIN_MAX_WAIT_TIME << 7);
        atomic_inc32(&fin_thread_info->end_waiting_num);
        IDATA status = hycond_wait_timed(&fin_thread_info->end_cond, &fin_thread_info->end_mutex, (I_64)wait_time, 0);
        atomic_dec32(&fin_thread_info->end_waiting_num);
        if(status != TM_ERROR_NONE) break;
        fin_obj_num = vm_get_finalizable_objects_quantity();
    }
    hymutex_unlock(&fin_thread_info->end_mutex);
}

void activate_finalizer_threads(Boolean wait)
{
    IDATA stat = hysem_set(fin_thread_info->pending_sem, fin_thread_info->thread_num);
    assert(stat == TM_ERROR_NONE);

    if(wait)
        wait_finalization_end();
}

static void notify_finalization_end(void)
{
    if(vm_get_finalizable_objects_quantity()==0 && fin_thread_info->working_thread_num==0)
        hycond_notify_all(&fin_thread_info->end_cond);
}

static void wait_pending_finalizer(void)
{
    IDATA stat = hysem_wait(fin_thread_info->pending_sem);
    assert(stat == TM_ERROR_NONE);
}

void assign_classloader_to_native_threads(JNIEnv *jni_env)
{
    jthread self_jthread = jthread_self();
    ManagedObject *self_obj = (*self_jthread).object;
    char *thread_jclass_name = "java/lang/Thread";
    jclass thread_jclass = FindClass(jni_env, thread_jclass_name);
    Class *thread_class = jclass_to_struct_Class(thread_jclass);
    Field *loader_field = LookupField(thread_class, "contextClassLoader");
    unsigned int offset = loader_field->get_offset();

    char *loader_jclass_name = "java/lang/ClassLoader";
    jclass loader_jclass = FindClass(jni_env, loader_jclass_name);
    Class *loader_class = jclass_to_struct_Class(loader_jclass);

    tmn_suspend_disable();

    Method *get_loader_method = LookupMethod(loader_class, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
    assert(get_loader_method);
    jvalue result;
    vm_execute_java_method_array((jmethodID)get_loader_method, &result, NULL);
    ManagedObject *sys_class_loader = (*(result.l)).object;

    uint32 *the_field = (uint32*)((POINTER_SIZE_INT)self_obj + offset);
    void *heap_null = Slot::managed_null();
    assert(sys_class_loader > heap_null);
    *the_field = (uint32)((POINTER_SIZE_INT)sys_class_loader - (POINTER_SIZE_INT)heap_null);

    tmn_suspend_enable();
}

static IDATA finalizer_thread_func(void **args)
{
    JavaVM *java_vm = (JavaVM *)args[0];
    JNIEnv *jni_env;
    //jthread java_thread;
    char *name = "finalizer";
    //jboolean daemon = JNI_TRUE;

    //IDATA status = vm_attach_internal(&jni_env, &java_thread, java_vm, NULL, name, daemon);
    //assert(status == JNI_OK);
    //status = jthread_attach(jni_env, java_thread, daemon);
    //assert(status == TM_ERROR_NONE);
    JavaVMAttachArgs *jni_args = (JavaVMAttachArgs*)STD_MALLOC(sizeof(JavaVMAttachArgs));
    jni_args->version = JNI_VERSION_1_2;
    jni_args->name = name;
    jni_args->group = NULL;
    IDATA status = AttachCurrentThreadAsDaemon(java_vm, (void**)&jni_env, jni_args);
    assert(status == JNI_OK);
    assign_classloader_to_native_threads(jni_env);
    inc_fin_thread_num();

    /* Choice: use VM_thread or hythread to indicate the finalizer thread ?
     * Now we use hythread
     * p_TLS_vmthread->finalize_thread_flags = thread_id;
     */

    while(true){
        /* Waiting for pending finalizers */
        wait_pending_finalizer();

        /* do the real finalization work */
        atomic_inc32(&fin_thread_info->working_thread_num);
        vm_do_finalization(0);
        atomic_dec32(&fin_thread_info->working_thread_num);

        vm_heavy_finalizer_resume_mutator();

        if(fin_thread_info->end_waiting_num)
            notify_finalization_end();

        if(fin_thread_info->shutdown)
            break;
    }

    vm_heavy_finalizer_resume_mutator();
    status = DetachCurrentThread(java_vm);
    dec_fin_thread_num();
    //status = jthread_detach(java_thread);
    return status;
}

/* Heavy finalizable object load handling mechanism */

/* Choice: use VM_thread or hythread to indicate the finalizer thread ?
 * Now we use hythread
 * p_TLS_vmthread->finalize_thread_flags = thread_id;
 */
static Boolean self_is_finalizer_thread(void)
{
    hythread_t self = hythread_self();

    for(unsigned int i=0; i<fin_thread_info->thread_num; ++i)
        if(self == fin_thread_info->thread_ids[i])
            return TRUE;

    return FALSE;
}

void vm_heavy_finalizer_block_mutator(void)
{
    /* Maybe self test is not needed. This needs further test. */
    if(self_is_finalizer_thread())
        return;

    hymutex_lock(&fin_thread_info->mutator_block_mutex);
    unsigned int fin_obj_num = vm_get_finalizable_objects_quantity();
    fin_obj_num = fin_obj_num >> (MUTATOR_BLOCK_THRESHOLD_BITS + cpu_num_bits);
    unsigned int wait_time = restrict_wait_time(fin_obj_num, FIN_MAX_WAIT_TIME);
    if(fin_obj_num)
        IDATA status = hycond_wait_timed_raw(&fin_thread_info->mutator_block_cond, &fin_thread_info->mutator_block_mutex, wait_time, 0);
    hymutex_unlock(&fin_thread_info->mutator_block_mutex);
}

void vm_heavy_finalizer_resume_mutator(void)
{
    if(gc_clear_mutator_block_flag())
        hycond_notify_all(&fin_thread_info->mutator_block_cond);
}

<commit_msg>HARMONY-3705 : the timing of finalizer is critical to pass the test. <commit_after>/*
 *  Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable.
 *
 *  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.
 */

/**
 * @author Li-Gang Wang, 2006/11/15
 */

#include "finalizer_thread.h"
#include "ref_enqueue_thread.h"
#include "finalize.h"
#include "vm_threads.h"
#include "init.h"
#include "open/jthread.h"
#include "jni_direct.h"
#include "jni_utils.h"
#include "slot.h"

static Boolean native_fin_thread_flag = FALSE;
static Fin_Thread_Info *fin_thread_info = NULL;
unsigned int cpu_num_bits;

static uint32 atomic_inc32(volatile apr_uint32_t *mem)
{  return (uint32)apr_atomic_inc32(mem); }

static uint32 atomic_dec32(volatile apr_uint32_t *mem)
{  return (uint32)apr_atomic_dec32(mem); }

Boolean get_native_finalizer_thread_flag()
{  return native_fin_thread_flag; }

void set_native_finalizer_thread_flag(Boolean flag)
{  native_fin_thread_flag = flag; }

Boolean get_finalizer_shutdown_flag()
{  return fin_thread_info->shutdown; }

Boolean get_finalizer_on_exit_flag()
{  return fin_thread_info->on_exit; }

static unsigned int coarse_log(unsigned int num)
{
    unsigned int i = sizeof(unsigned int) << 3;
    unsigned int comp = 1 << (i-1);
    while(i--){
        if(num & comp)
            return i;
        num = num << 1;
    }
    return 0;
}

static IDATA finalizer_thread_func(void **args);
static void wait_fin_threads_attached(void);

void finalizer_threads_init(JavaVM *java_vm)
{
    if(!native_fin_thread_flag)
        return;

    fin_thread_info = (Fin_Thread_Info *)STD_MALLOC(sizeof(Fin_Thread_Info));
    fin_thread_info->thread_num = port_CPUs_number();
    cpu_num_bits = coarse_log(fin_thread_info->thread_num);
    fin_thread_info->working_thread_num = 0;
    fin_thread_info->end_waiting_num = 0;
    fin_thread_info->shutdown = FALSE;
    fin_thread_info->on_exit = FALSE;

    IDATA status = hysem_create(&fin_thread_info->pending_sem, 0, fin_thread_info->thread_num);
    assert(status == TM_ERROR_NONE);

    status = hycond_create(&fin_thread_info->end_cond);
    assert(status == TM_ERROR_NONE);
    status = hymutex_create(&fin_thread_info->end_mutex, TM_MUTEX_DEFAULT);
    assert(status == TM_ERROR_NONE);

    status = hycond_create(&fin_thread_info->mutator_block_cond);
    assert(status == TM_ERROR_NONE);
    status = hymutex_create(&fin_thread_info->mutator_block_mutex, TM_MUTEX_DEFAULT);
    assert(status == TM_ERROR_NONE);

    fin_thread_info->thread_ids = (hythread_t *)STD_MALLOC(sizeof(hythread_t) * fin_thread_info->thread_num);
    fin_thread_info->thread_attached_num = 0;

    for(unsigned int i = 0; i < fin_thread_info->thread_num; i++){
        void **args = (void **)STD_MALLOC(sizeof(void *) * 2);
        args[0] = (void *)java_vm;
        args[1] = (void *)(UDATA)(i + 1);
        fin_thread_info->thread_ids[i] = NULL;
        status = hythread_create(&fin_thread_info->thread_ids[i], 0, FINALIZER_THREAD_PRIORITY, 0, (hythread_entrypoint_t)finalizer_thread_func, args);
        assert(status == TM_ERROR_NONE);
    }

    wait_fin_threads_attached();
}

void finalizer_shutdown(Boolean start_finalization_on_exit)
{
    if(start_finalization_on_exit){
        tmn_suspend_disable();
        gc_force_gc();
        tmn_suspend_enable();
        activate_finalizer_threads(TRUE);
        tmn_suspend_disable();
        gc_finalize_on_exit();
        tmn_suspend_enable();
        fin_thread_info->on_exit = TRUE;
        activate_finalizer_threads(TRUE);
    }
    fin_thread_info->shutdown = TRUE;
    ref_enqueue_shutdown();
    activate_finalizer_threads(TRUE);
}

static void inc_fin_thread_num(void)
{ atomic_inc32(&fin_thread_info->thread_attached_num); }

static void dec_fin_thread_num(void)
{ atomic_dec32(&fin_thread_info->thread_attached_num); }

static void wait_fin_threads_attached(void)
{ while(fin_thread_info->thread_attached_num < fin_thread_info->thread_num); }

void wait_native_fin_threads_detached(void)
{
    hymutex_lock(&fin_thread_info->end_mutex);
    while(fin_thread_info->thread_attached_num){
        atomic_inc32(&fin_thread_info->end_waiting_num);
        IDATA status = hycond_wait_timed(&fin_thread_info->end_cond, &fin_thread_info->end_mutex, (I_64)1000, 0);
        atomic_dec32(&fin_thread_info->end_waiting_num);
        if(status != TM_ERROR_NONE) break;
    }
    hymutex_unlock(&fin_thread_info->end_mutex);
}

/* Restrict waiting time; Unit: msec */
static unsigned int restrict_wait_time(unsigned int wait_time, unsigned int max_time)
{
    if(!wait_time) return 1;
    if(wait_time > max_time) return max_time;
    return wait_time;
}

static void wait_finalization_end(Boolean must_wait)
{
    hymutex_lock(&fin_thread_info->end_mutex);
    unsigned int fin_obj_num = vm_get_finalizable_objects_quantity();
    while(fin_thread_info->working_thread_num || fin_obj_num){
        unsigned int wait_time = restrict_wait_time(fin_obj_num, FIN_MAX_WAIT_TIME << 7);
        atomic_inc32(&fin_thread_info->end_waiting_num);
        IDATA status = hycond_wait_timed(&fin_thread_info->end_cond, &fin_thread_info->end_mutex, (I_64)wait_time, 0);
        atomic_dec32(&fin_thread_info->end_waiting_num);
        unsigned int temp = vm_get_finalizable_objects_quantity();
        if(must_wait){
            if((status != TM_ERROR_NONE) && (fin_obj_num == temp)) break;
        }else{
            if(status != TM_ERROR_NONE) break;
        }
        fin_obj_num = temp;
    }
    hymutex_unlock(&fin_thread_info->end_mutex);
}

void activate_finalizer_threads(Boolean wait)
{
    IDATA stat = hysem_set(fin_thread_info->pending_sem, fin_thread_info->thread_num);
    assert(stat == TM_ERROR_NONE);

    if(wait)
        wait_finalization_end(true);
}

static void notify_finalization_end(void)
{
    if(vm_get_finalizable_objects_quantity()==0 && fin_thread_info->working_thread_num==0)
        hycond_notify_all(&fin_thread_info->end_cond);
}

static void wait_pending_finalizer(void)
{
    IDATA stat = hysem_wait(fin_thread_info->pending_sem);
    assert(stat == TM_ERROR_NONE);
}

void assign_classloader_to_native_threads(JNIEnv *jni_env)
{
    jthread self_jthread = jthread_self();
    ManagedObject *self_obj = (*self_jthread).object;
    char *thread_jclass_name = "java/lang/Thread";
    jclass thread_jclass = FindClass(jni_env, thread_jclass_name);
    Class *thread_class = jclass_to_struct_Class(thread_jclass);
    Field *loader_field = LookupField(thread_class, "contextClassLoader");
    unsigned int offset = loader_field->get_offset();

    char *loader_jclass_name = "java/lang/ClassLoader";
    jclass loader_jclass = FindClass(jni_env, loader_jclass_name);
    Class *loader_class = jclass_to_struct_Class(loader_jclass);

    tmn_suspend_disable();

    Method *get_loader_method = LookupMethod(loader_class, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
    assert(get_loader_method);
    jvalue result;
    vm_execute_java_method_array((jmethodID)get_loader_method, &result, NULL);
    ManagedObject *sys_class_loader = (*(result.l)).object;

    uint32 *the_field = (uint32*)((POINTER_SIZE_INT)self_obj + offset);
    void *heap_null = Slot::managed_null();
    assert(sys_class_loader > heap_null);
    *the_field = (uint32)((POINTER_SIZE_INT)sys_class_loader - (POINTER_SIZE_INT)heap_null);

    tmn_suspend_enable();
}

static IDATA finalizer_thread_func(void **args)
{
    JavaVM *java_vm = (JavaVM *)args[0];
    JNIEnv *jni_env;
    //jthread java_thread;
    char *name = "finalizer";
    //jboolean daemon = JNI_TRUE;

    //IDATA status = vm_attach_internal(&jni_env, &java_thread, java_vm, NULL, name, daemon);
    //assert(status == JNI_OK);
    //status = jthread_attach(jni_env, java_thread, daemon);
    //assert(status == TM_ERROR_NONE);
    JavaVMAttachArgs *jni_args = (JavaVMAttachArgs*)STD_MALLOC(sizeof(JavaVMAttachArgs));
    jni_args->version = JNI_VERSION_1_2;
    jni_args->name = name;
    jni_args->group = NULL;
    IDATA status = AttachCurrentThreadAsDaemon(java_vm, (void**)&jni_env, jni_args);
    assert(status == JNI_OK);
    assign_classloader_to_native_threads(jni_env);
    inc_fin_thread_num();

    /* Choice: use VM_thread or hythread to indicate the finalizer thread ?
     * Now we use hythread
     * p_TLS_vmthread->finalize_thread_flags = thread_id;
     */

    while(true){
        /* Waiting for pending finalizers */
        wait_pending_finalizer();

        /* do the real finalization work */
        atomic_inc32(&fin_thread_info->working_thread_num);
        vm_do_finalization(0);
        atomic_dec32(&fin_thread_info->working_thread_num);

        vm_heavy_finalizer_resume_mutator();

        if(fin_thread_info->end_waiting_num)
            notify_finalization_end();

        if(fin_thread_info->shutdown)
            break;
    }

    vm_heavy_finalizer_resume_mutator();
    status = DetachCurrentThread(java_vm);
    dec_fin_thread_num();
    //status = jthread_detach(java_thread);
    return status;
}

/* Heavy finalizable object load handling mechanism */

/* Choice: use VM_thread or hythread to indicate the finalizer thread ?
 * Now we use hythread
 * p_TLS_vmthread->finalize_thread_flags = thread_id;
 */
static Boolean self_is_finalizer_thread(void)
{
    hythread_t self = hythread_self();

    for(unsigned int i=0; i<fin_thread_info->thread_num; ++i)
        if(self == fin_thread_info->thread_ids[i])
            return TRUE;

    return FALSE;
}

void vm_heavy_finalizer_block_mutator(void)
{
    /* Maybe self test is not needed. This needs further test. */
    if(self_is_finalizer_thread())
        return;

    hymutex_lock(&fin_thread_info->mutator_block_mutex);
    unsigned int fin_obj_num = vm_get_finalizable_objects_quantity();
    fin_obj_num = fin_obj_num >> (MUTATOR_BLOCK_THRESHOLD_BITS + cpu_num_bits);
    unsigned int wait_time = restrict_wait_time(fin_obj_num, FIN_MAX_WAIT_TIME);
    if(fin_obj_num)
        IDATA status = hycond_wait_timed_raw(&fin_thread_info->mutator_block_cond, &fin_thread_info->mutator_block_mutex, wait_time, 0);
    hymutex_unlock(&fin_thread_info->mutator_block_mutex);
}

void vm_heavy_finalizer_resume_mutator(void)
{
    if(gc_clear_mutator_block_flag())
        hycond_notify_all(&fin_thread_info->mutator_block_cond);
}

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "probe.h"

#include "clangclprobe.h"
#include "gccprobe.h"
#include "iarewprobe.h"
#include "keilprobe.h"
#include "msvcprobe.h"
#include "sdccprobe.h"
#include "xcodeprobe.h"

#include <logging/translator.h>
#include <tools/error.h>
#include <tools/hostosinfo.h>
#include <tools/profile.h>
#include <tools/qttools.h>
#include <tools/settings.h>
#include <tools/toolchains.h>

#include <QtCore/qdir.h>
#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/qtextstream.h>

#ifdef Q_OS_WIN
// We need defines for Windows 8.
#undef _WIN32_WINNT
#define _WIN32_WINNT _WIN32_WINNT_WIN8

#include <qt_windows.h>
#include <shlobj.h>
#else
#include <qplatformdefs.h>
#endif // Q_OS_WIN

using namespace qbs;
using Internal::HostOsInfo;
using Internal::Tr;

static QTextStream qStdout(stdout);
static QTextStream qStderr(stderr);

QStringList systemSearchPaths()
{
    return QString::fromLocal8Bit(qgetenv("PATH")).split(HostOsInfo::pathListSeparator());
}

QString findExecutable(const QString &fileName)
{
    QString fullFileName = fileName;
    if (HostOsInfo::isWindowsHost()
            && !fileName.endsWith(QLatin1String(".exe"), Qt::CaseInsensitive)) {
        fullFileName += QLatin1String(".exe");
    }
    const auto ppaths = systemSearchPaths();
    for (const QString &ppath : ppaths) {
        const QString fullPath = ppath + QLatin1Char('/') + fullFileName;
        if (QFileInfo::exists(fullPath))
            return QDir::cleanPath(fullPath);
    }
    return {};
}

QString toolchainTypeFromCompilerName(const QString &compilerName)
{
    if (compilerName == QLatin1String("cl.exe"))
        return QStringLiteral("msvc");
    if (compilerName == QLatin1String("clang-cl.exe"))
        return QStringLiteral("clang-cl");
    const auto types = { QStringLiteral("clang"), QStringLiteral("llvm"),
                         QStringLiteral("mingw"), QStringLiteral("gcc") };
    for (const auto &type : types) {
        if (compilerName.contains(type))
            return type;
    }
    if (compilerName == QLatin1String("g++"))
        return QStringLiteral("gcc");
    if (isIarCompiler(compilerName))
        return QStringLiteral("iar");
    if (isKeilCompiler(compilerName))
        return QStringLiteral("keil");
    if (isSdccCompiler(compilerName))
        return QStringLiteral("sdcc");
    return {};
}

void probe(Settings *settings)
{
    std::vector<Profile> profiles;
    if (HostOsInfo::isWindowsHost()) {
        msvcProbe(settings, profiles);
        clangClProbe(settings, profiles);
    } else if (HostOsInfo::isMacosHost()) {
        xcodeProbe(settings, profiles);
    }

    gccProbe(settings, profiles, QStringLiteral("gcc"));
    gccProbe(settings, profiles, QStringLiteral("clang"));

    iarProbe(settings, profiles);
    keilProbe(settings, profiles);
    sdccProbe(settings, profiles);

    if (profiles.empty()) {
        qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << Qt::endl;
    } else if (profiles.size() == 1 && settings->defaultProfile().isEmpty()) {
        const QString profileName = profiles.front().name();
        qStdout << Tr::tr("Making profile '%1' the default.").arg(profileName) << Qt::endl;
        settings->setValue(QStringLiteral("defaultProfile"), profileName);
    }
}

void createProfile(const QString &profileName, const QString &toolchainType,
                   const QString &compilerFilePath, Settings *settings)
{
    QFileInfo compiler(compilerFilePath);
    if (compilerFilePath == compiler.fileName() && !compiler.exists())
        compiler = QFileInfo(findExecutable(compilerFilePath));

    if (!compiler.exists()) {
        throw qbs::ErrorInfo(Tr::tr("Compiler '%1' not found")
                             .arg(compilerFilePath));
    }

    const QString realToolchainType = !toolchainType.isEmpty()
            ? toolchainType
            : toolchainTypeFromCompilerName(compiler.fileName());
    const QStringList toolchain = canonicalToolchain(realToolchainType);

    if (toolchain.contains(QLatin1String("msvc")))
        createMsvcProfile(compiler, settings, profileName);
    else if (toolchain.contains(QLatin1String("clang-cl")))
        createClangClProfile(compiler, settings, profileName);
    else if (toolchain.contains(QLatin1String("gcc")))
        createGccProfile(compiler, settings, realToolchainType, profileName);
    else if (toolchain.contains(QLatin1String("iar")))
        createIarProfile(compiler, settings, profileName);
    else if (toolchain.contains(QLatin1String("keil")))
        createKeilProfile(compiler, settings, profileName);
    else if (toolchain.contains(QLatin1String("sdcc")))
        createSdccProfile(compiler, settings, profileName);
    else
        throw qbs::ErrorInfo(Tr::tr("Cannot create profile: Unknown toolchain type."));
}

int extractVersion(const QByteArray &macroDump, const QByteArray &keyToken)
{
    const int startIndex = macroDump.indexOf(keyToken);
    if (startIndex == -1)
        return -1;
    const int endIndex = macroDump.indexOf('\n', startIndex);
    if (endIndex == -1)
        return -1;
    const auto keyLength = keyToken.length();
    const int version = macroDump.mid(startIndex + keyLength,
                                      endIndex - startIndex - keyLength)
            .toInt();
    return version;
}

static QString resolveSymlinks(const QString &filePath)
{
    QFileInfo fi(filePath);
    int links = 16;
    while (links-- && fi.isSymLink())
        fi.setFile(fi.dir(), fi.symLinkTarget());
    if (links <= 0)
        return {};
    return fi.filePath();
}

// Copied from qfilesystemengine_win.cpp.
#ifdef Q_OS_WIN

// File ID for Windows up to version 7.
static inline QByteArray fileIdWin7(HANDLE handle)
{
    BY_HANDLE_FILE_INFORMATION info;
    if (GetFileInformationByHandle(handle, &info)) {
        char buffer[sizeof "01234567:0123456701234567\0"];
        qsnprintf(buffer, sizeof(buffer), "%lx:%08lx%08lx",
                  info.dwVolumeSerialNumber,
                  info.nFileIndexHigh,
                  info.nFileIndexLow);
        return QByteArray(buffer);
    }
    return {};
}

// File ID for Windows starting from version 8.
static QByteArray fileIdWin8(HANDLE handle)
{
    QByteArray result;
    FILE_ID_INFO infoEx = {};
    if (::GetFileInformationByHandleEx(
                handle,
                static_cast<FILE_INFO_BY_HANDLE_CLASS>(18), // FileIdInfo in Windows 8
                &infoEx, sizeof(FILE_ID_INFO))) {
        result = QByteArray::number(infoEx.VolumeSerialNumber, 16);
        result += ':';
        // Note: MinGW-64's definition of FILE_ID_128 differs from the MSVC one.
        result += QByteArray(reinterpret_cast<const char *>(&infoEx.FileId),
                             int(sizeof(infoEx.FileId))).toHex();
    }
    return result;
}

static QByteArray fileIdWin(HANDLE fHandle)
{
    return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8
            ? fileIdWin8(HANDLE(fHandle))
            : fileIdWin7(HANDLE(fHandle));
}

static QByteArray fileId(const QString &filePath)
{
    QByteArray result;
    const HANDLE handle = ::CreateFile(
                reinterpret_cast<const wchar_t*>(filePath.utf16()), 0,
                FILE_SHARE_READ, nullptr, OPEN_EXISTING,
                FILE_FLAG_BACKUP_SEMANTICS, nullptr);
    if (handle != INVALID_HANDLE_VALUE) {
        result = fileIdWin(handle);
        ::CloseHandle(handle);
    }
    return result;
}

static qint64 fileSize(const QString &filePath)
{
    return QFileInfo(filePath).size();
}

#else

static QByteArray fileId(const QString &filePath)
{
    QByteArray result;
    if (Q_UNLIKELY(filePath.isEmpty()))
        return {};
    QT_STATBUF statResult = {};
    if (QT_STAT(filePath.toLocal8Bit().constData(), &statResult))
        return {};
    result = QByteArray::number(quint64(statResult.st_dev), 16);
    result += ':';
    result += QByteArray::number(quint64(statResult.st_ino));
    return result;
}

#endif // Q_OS_WIN

bool isSameExecutable(const QString &filePath1, const QString &filePath2)
{
    if (filePath1 == filePath2)
        return true;
    if (resolveSymlinks(filePath1) == resolveSymlinks(filePath2))
        return true;
    if (fileId(filePath1) == fileId(filePath2))
        return true;

#ifdef Q_OS_WIN
    if (fileSize(filePath1) == fileSize(filePath2))
        return true;
#endif

    return false;
}
<commit_msg>Reorder toolchain-check to enable creating of clang-cl profile<commit_after>/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "probe.h"

#include "clangclprobe.h"
#include "gccprobe.h"
#include "iarewprobe.h"
#include "keilprobe.h"
#include "msvcprobe.h"
#include "sdccprobe.h"
#include "xcodeprobe.h"

#include <logging/translator.h>
#include <tools/error.h>
#include <tools/hostosinfo.h>
#include <tools/profile.h>
#include <tools/qttools.h>
#include <tools/settings.h>
#include <tools/toolchains.h>

#include <QtCore/qdir.h>
#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/qtextstream.h>

#ifdef Q_OS_WIN
// We need defines for Windows 8.
#undef _WIN32_WINNT
#define _WIN32_WINNT _WIN32_WINNT_WIN8

#include <qt_windows.h>
#include <shlobj.h>
#else
#include <qplatformdefs.h>
#endif // Q_OS_WIN

using namespace qbs;
using Internal::HostOsInfo;
using Internal::Tr;

static QTextStream qStdout(stdout);
static QTextStream qStderr(stderr);

QStringList systemSearchPaths()
{
    return QString::fromLocal8Bit(qgetenv("PATH")).split(HostOsInfo::pathListSeparator());
}

QString findExecutable(const QString &fileName)
{
    QString fullFileName = fileName;
    if (HostOsInfo::isWindowsHost()
            && !fileName.endsWith(QLatin1String(".exe"), Qt::CaseInsensitive)) {
        fullFileName += QLatin1String(".exe");
    }
    const auto ppaths = systemSearchPaths();
    for (const QString &ppath : ppaths) {
        const QString fullPath = ppath + QLatin1Char('/') + fullFileName;
        if (QFileInfo::exists(fullPath))
            return QDir::cleanPath(fullPath);
    }
    return {};
}

QString toolchainTypeFromCompilerName(const QString &compilerName)
{
    if (compilerName == QLatin1String("cl.exe"))
        return QStringLiteral("msvc");
    if (compilerName == QLatin1String("clang-cl.exe"))
        return QStringLiteral("clang-cl");
    const auto types = { QStringLiteral("clang"), QStringLiteral("llvm"),
                         QStringLiteral("mingw"), QStringLiteral("gcc") };
    for (const auto &type : types) {
        if (compilerName.contains(type))
            return type;
    }
    if (compilerName == QLatin1String("g++"))
        return QStringLiteral("gcc");
    if (isIarCompiler(compilerName))
        return QStringLiteral("iar");
    if (isKeilCompiler(compilerName))
        return QStringLiteral("keil");
    if (isSdccCompiler(compilerName))
        return QStringLiteral("sdcc");
    return {};
}

void probe(Settings *settings)
{
    std::vector<Profile> profiles;
    if (HostOsInfo::isWindowsHost()) {
        msvcProbe(settings, profiles);
        clangClProbe(settings, profiles);
    } else if (HostOsInfo::isMacosHost()) {
        xcodeProbe(settings, profiles);
    }

    gccProbe(settings, profiles, QStringLiteral("gcc"));
    gccProbe(settings, profiles, QStringLiteral("clang"));

    iarProbe(settings, profiles);
    keilProbe(settings, profiles);
    sdccProbe(settings, profiles);

    if (profiles.empty()) {
        qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << Qt::endl;
    } else if (profiles.size() == 1 && settings->defaultProfile().isEmpty()) {
        const QString profileName = profiles.front().name();
        qStdout << Tr::tr("Making profile '%1' the default.").arg(profileName) << Qt::endl;
        settings->setValue(QStringLiteral("defaultProfile"), profileName);
    }
}

void createProfile(const QString &profileName, const QString &toolchainType,
                   const QString &compilerFilePath, Settings *settings)
{
    QFileInfo compiler(compilerFilePath);
    if (compilerFilePath == compiler.fileName() && !compiler.exists())
        compiler = QFileInfo(findExecutable(compilerFilePath));

    if (!compiler.exists()) {
        throw qbs::ErrorInfo(Tr::tr("Compiler '%1' not found")
                             .arg(compilerFilePath));
    }

    const QString realToolchainType = !toolchainType.isEmpty()
            ? toolchainType
            : toolchainTypeFromCompilerName(compiler.fileName());
    const QStringList toolchain = canonicalToolchain(realToolchainType);

    if (toolchain.contains(QLatin1String("clang-cl")))
        createClangClProfile(compiler, settings, profileName);
    else if (toolchain.contains(QLatin1String("msvc")))
        createMsvcProfile(compiler, settings, profileName);
    else if (toolchain.contains(QLatin1String("gcc")))
        createGccProfile(compiler, settings, realToolchainType, profileName);
    else if (toolchain.contains(QLatin1String("iar")))
        createIarProfile(compiler, settings, profileName);
    else if (toolchain.contains(QLatin1String("keil")))
        createKeilProfile(compiler, settings, profileName);
    else if (toolchain.contains(QLatin1String("sdcc")))
        createSdccProfile(compiler, settings, profileName);
    else
        throw qbs::ErrorInfo(Tr::tr("Cannot create profile: Unknown toolchain type."));
}

int extractVersion(const QByteArray &macroDump, const QByteArray &keyToken)
{
    const int startIndex = macroDump.indexOf(keyToken);
    if (startIndex == -1)
        return -1;
    const int endIndex = macroDump.indexOf('\n', startIndex);
    if (endIndex == -1)
        return -1;
    const auto keyLength = keyToken.length();
    const int version = macroDump.mid(startIndex + keyLength,
                                      endIndex - startIndex - keyLength)
            .toInt();
    return version;
}

static QString resolveSymlinks(const QString &filePath)
{
    QFileInfo fi(filePath);
    int links = 16;
    while (links-- && fi.isSymLink())
        fi.setFile(fi.dir(), fi.symLinkTarget());
    if (links <= 0)
        return {};
    return fi.filePath();
}

// Copied from qfilesystemengine_win.cpp.
#ifdef Q_OS_WIN

// File ID for Windows up to version 7.
static inline QByteArray fileIdWin7(HANDLE handle)
{
    BY_HANDLE_FILE_INFORMATION info;
    if (GetFileInformationByHandle(handle, &info)) {
        char buffer[sizeof "01234567:0123456701234567\0"];
        qsnprintf(buffer, sizeof(buffer), "%lx:%08lx%08lx",
                  info.dwVolumeSerialNumber,
                  info.nFileIndexHigh,
                  info.nFileIndexLow);
        return QByteArray(buffer);
    }
    return {};
}

// File ID for Windows starting from version 8.
static QByteArray fileIdWin8(HANDLE handle)
{
    QByteArray result;
    FILE_ID_INFO infoEx = {};
    if (::GetFileInformationByHandleEx(
                handle,
                static_cast<FILE_INFO_BY_HANDLE_CLASS>(18), // FileIdInfo in Windows 8
                &infoEx, sizeof(FILE_ID_INFO))) {
        result = QByteArray::number(infoEx.VolumeSerialNumber, 16);
        result += ':';
        // Note: MinGW-64's definition of FILE_ID_128 differs from the MSVC one.
        result += QByteArray(reinterpret_cast<const char *>(&infoEx.FileId),
                             int(sizeof(infoEx.FileId))).toHex();
    }
    return result;
}

static QByteArray fileIdWin(HANDLE fHandle)
{
    return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8
            ? fileIdWin8(HANDLE(fHandle))
            : fileIdWin7(HANDLE(fHandle));
}

static QByteArray fileId(const QString &filePath)
{
    QByteArray result;
    const HANDLE handle = ::CreateFile(
                reinterpret_cast<const wchar_t*>(filePath.utf16()), 0,
                FILE_SHARE_READ, nullptr, OPEN_EXISTING,
                FILE_FLAG_BACKUP_SEMANTICS, nullptr);
    if (handle != INVALID_HANDLE_VALUE) {
        result = fileIdWin(handle);
        ::CloseHandle(handle);
    }
    return result;
}

static qint64 fileSize(const QString &filePath)
{
    return QFileInfo(filePath).size();
}

#else

static QByteArray fileId(const QString &filePath)
{
    QByteArray result;
    if (Q_UNLIKELY(filePath.isEmpty()))
        return {};
    QT_STATBUF statResult = {};
    if (QT_STAT(filePath.toLocal8Bit().constData(), &statResult))
        return {};
    result = QByteArray::number(quint64(statResult.st_dev), 16);
    result += ':';
    result += QByteArray::number(quint64(statResult.st_ino));
    return result;
}

#endif // Q_OS_WIN

bool isSameExecutable(const QString &filePath1, const QString &filePath2)
{
    if (filePath1 == filePath2)
        return true;
    if (resolveSymlinks(filePath1) == resolveSymlinks(filePath2))
        return true;
    if (fileId(filePath1) == fileId(filePath2))
        return true;

#ifdef Q_OS_WIN
    if (fileSize(filePath1) == fileSize(filePath2))
        return true;
#endif

    return false;
}
<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2012 Francois Beaune, Jupiter Jazz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "renderwidget.h"

// appleseed.studio headers.
#include "utility/interop.h"

// appleseed.renderer headers.
#include "renderer/api/frame.h"

// appleseed.foundation headers.
#include "foundation/image/canvasproperties.h"
#include "foundation/image/image.h"
#include "foundation/image/nativedrawing.h"
#include "foundation/image/tile.h"

// Qt headers.
#include <Qt>

// Standard headers.
#include <algorithm>
#include <cassert>

using namespace foundation;
using namespace renderer;
using namespace std;

namespace appleseed {
namespace studio {

//
// RenderWidget class implementation.
//

RenderWidget::RenderWidget(
    const int       width,
    const int       height,
    QWidget*        parent)
  : QWidget(parent)
  , m_image(width, height, QImage::Format_RGB888)
{
    setFocusPolicy(Qt::StrongFocus);

    setFixedWidth(width);
    setFixedHeight(height);

    setAutoFillBackground(false);
    setAttribute(Qt::WA_OpaquePaintEvent, true);

    clear(Color4f(0.0f));
}

void RenderWidget::clear(const Color4f& color)
{
    m_image_mutex.lock();
    m_image.fill(color_to_qcolor(color).rgba());
    m_image_mutex.unlock();
}

namespace
{
    inline uint8* get_image_pointer(
        QImage&         image,
        const size_t    x,
        const size_t    y)
    {
        uint8* scanline = static_cast<uint8*>(image.scanLine(static_cast<int>(y)));
        return scanline + x * image.depth() / 8;
    }
}

void RenderWidget::highlight_region(
    const size_t    x,
    const size_t    y,
    const size_t    width,
    const size_t    height)
{
    m_image_mutex.lock();

    // Retrieve destination image information.
    const size_t dest_width = static_cast<size_t>(m_image.width());
    const size_t dest_height = static_cast<size_t>(m_image.height());
    const size_t dest_stride = static_cast<size_t>(m_image.bytesPerLine());

    // Clipping is not supported.
    assert(x < dest_width);
    assert(y < dest_height);
    assert(x + width <= dest_width);
    assert(y + height <= dest_height);

    // Get a pointer to the first destination pixel.
    uint8* dest = get_image_pointer(m_image, x, y);

    // Clear the tile in black.
    const uint8 Black[3] = { 0, 0, 0 };
    NativeDrawing::clear(
        dest,
        width,
        height,
        dest_stride,
        Black,
        sizeof(Black));

    // Draw a white rectangle around the tile.
    const uint8 White[3] = { 255, 255, 255 };
    NativeDrawing::draw_hline(
        dest,
        width,
        White,
        sizeof(White));
    NativeDrawing::draw_hline(
        dest + (height - 1) * dest_stride,
        width,
        White,
        sizeof(White));
    NativeDrawing::draw_vline(
        dest,
        dest_stride,
        height,
        White,
        sizeof(White));
    NativeDrawing::draw_vline(
        dest + (width - 1) * sizeof(White),
        dest_stride,
        height,
        White,
        sizeof(White));

    m_image_mutex.unlock();
}

void RenderWidget::blit_tile(
    const Frame&    frame,
    const size_t    tile_x,
    const size_t    tile_y)
{
    m_image_mutex.lock();
    blit_tile_no_lock(frame, tile_x, tile_y);
    m_image_mutex.unlock();
}

void RenderWidget::blit_frame(
    const Frame&    frame)
{
    const CanvasProperties& frame_props = frame.image().properties();

    Tile float_tile_storage(
        frame_props.m_tile_width,
        frame_props.m_tile_height,
        frame_props.m_channel_count,
        PixelFormatFloat);

    Tile uint8_tile_storage(
        frame_props.m_tile_width,
        frame_props.m_tile_height,
        frame_props.m_channel_count,
        PixelFormatUInt8);

    m_image_mutex.lock();

    for (size_t ty = 0; ty < frame_props.m_tile_count_y; ++ty)
    {
        for (size_t tx = 0; tx < frame_props.m_tile_count_x; ++tx)
        {
            blit_tile_no_lock(
                frame,
                tx,
                ty,
                float_tile_storage.get_storage(),
                uint8_tile_storage.get_storage());
        }
    }

    m_image_mutex.unlock();
}

void RenderWidget::blit_tile_no_lock(
    const Frame&    frame,
    const size_t    tile_x,
    const size_t    tile_y,
    uint8*          float_tile_storage,
    uint8*          uint8_tile_storage)
{
    // Retrieve the source tile.
    const Tile& tile = frame.image().tile(tile_x, tile_y);

    // Convert the tile to 32-bit floating point.
    Tile fp_rgb_tile(
        tile,
        PixelFormatFloat,
        float_tile_storage);

    // Transform the tile to the color space of the frame.
    frame.transform_to_output_color_space(fp_rgb_tile);

    // Convert the tile to 8-bit RGB for display.
    static const size_t ShuffleTable[] = { 0, 1, 2, Pixel::SkipChannel };
    const Tile uint8_rgb_tile(
        fp_rgb_tile,
        PixelFormatUInt8,
        ShuffleTable,
        uint8_tile_storage);

    // Retrieve destination image information.
    const size_t dest_width = static_cast<size_t>(m_image.width());
    const size_t dest_height = static_cast<size_t>(m_image.height());
    const size_t dest_stride = static_cast<size_t>(m_image.bytesPerLine());

    // Compute the coordinates of the first destination pixel.
    const CanvasProperties& frame_props = frame.image().properties();
    const size_t x = tile_x * frame_props.m_tile_width;
    const size_t y = tile_y * frame_props.m_tile_height;

    // Clipping is not supported.
    assert(x < dest_width);
    assert(y < dest_height);
    assert(x + tile.get_width() <= dest_width);
    assert(y + tile.get_height() <= dest_height);

    // Get a pointer to the first destination pixel.
    uint8* dest = get_image_pointer(m_image, x, y);

    // Blit the tile to the destination image.
    NativeDrawing::blit(dest, dest_stride, uint8_rgb_tile);
}

void RenderWidget::paintEvent(QPaintEvent* event)
{
    m_image_mutex.lock();

    m_painter.begin(this);
    m_painter.drawImage(rect(), m_image);
    m_painter.end();

    m_image_mutex.unlock();
}

}   // namespace studio
}   // namespace appleseed
<commit_msg>draw a bracket around the tile being rendered instead of a white rectangle.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2012 Francois Beaune, Jupiter Jazz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "renderwidget.h"

// appleseed.studio headers.
#include "utility/interop.h"

// appleseed.renderer headers.
#include "renderer/api/frame.h"

// appleseed.foundation headers.
#include "foundation/image/canvasproperties.h"
#include "foundation/image/image.h"
#include "foundation/image/nativedrawing.h"
#include "foundation/image/tile.h"

// Qt headers.
#include <Qt>

// Standard headers.
#include <algorithm>
#include <cassert>

using namespace foundation;
using namespace renderer;
using namespace std;

namespace appleseed {
namespace studio {

//
// RenderWidget class implementation.
//

RenderWidget::RenderWidget(
    const int       width,
    const int       height,
    QWidget*        parent)
  : QWidget(parent)
  , m_image(width, height, QImage::Format_RGB888)
{
    setFocusPolicy(Qt::StrongFocus);

    setFixedWidth(width);
    setFixedHeight(height);

    setAutoFillBackground(false);
    setAttribute(Qt::WA_OpaquePaintEvent, true);

    clear(Color4f(0.0f));
}

void RenderWidget::clear(const Color4f& color)
{
    m_image_mutex.lock();
    m_image.fill(color_to_qcolor(color).rgba());
    m_image_mutex.unlock();
}

namespace
{
    inline uint8* get_image_pointer(
        QImage&         image,
        const size_t    x,
        const size_t    y)
    {
        uint8* scanline = static_cast<uint8*>(image.scanLine(static_cast<int>(y)));
        return scanline + x * image.depth() / 8;
    }

    void draw_bracket(
        uint8*          dest,
        const size_t    dest_width,
        const size_t    dest_height,
        const size_t    dest_stride,
        const size_t    bracket_extent,
        const uint8*    pixel,
        const size_t    pixel_size)
    {
        const int w = static_cast<int>(min(bracket_extent, dest_width));
        const int h = static_cast<int>(min(bracket_extent, dest_height));

        const size_t right = (dest_width - 1) * pixel_size;
        const size_t bottom = (dest_height - 1) * dest_stride;

        // Top-left corner.
        NativeDrawing::draw_hline(dest, w, pixel, pixel_size);
        NativeDrawing::draw_vline(dest, dest_stride, h, pixel, pixel_size);

        // Top-right corner.
        NativeDrawing::draw_hline(dest + right, -w, pixel, pixel_size);
        NativeDrawing::draw_vline(dest + right, dest_stride, h, pixel, pixel_size);

        // Bottom-left corner.
        NativeDrawing::draw_hline(dest + bottom, w, pixel, pixel_size);
        NativeDrawing::draw_vline(dest + bottom, dest_stride, -h, pixel, pixel_size);

        // Bottom-right corner.
        NativeDrawing::draw_hline(dest + bottom + right, -w, pixel, pixel_size);
        NativeDrawing::draw_vline(dest + bottom + right, dest_stride, -h, pixel, pixel_size);
    }
}

void RenderWidget::highlight_region(
    const size_t    x,
    const size_t    y,
    const size_t    width,
    const size_t    height)
{
    m_image_mutex.lock();

    // Retrieve destination image information.
    const size_t image_width = static_cast<size_t>(m_image.width());
    const size_t image_height = static_cast<size_t>(m_image.height());
    const size_t dest_stride = static_cast<size_t>(m_image.bytesPerLine());

    // Clipping is not supported.
    assert(x < image_width);
    assert(y < image_height);
    assert(x + width <= image_width);
    assert(y + height <= image_height);

    // Get a pointer to the first destination pixel.
    uint8* dest = get_image_pointer(m_image, x, y);

/*
    // Clear the tile.
    const uint8 ClearColor[3] = { 0, 0, 0 };
    NativeDrawing::clear(
        dest,
        width,
        height,
        dest_stride,
        ClearColor,
        sizeof(ClearColor));
*/

    // Draw a bracket around the tile.
    const uint8 BracketColor[3] = { 255, 255, 255 };
    const size_t BracketExtent = 5;
    draw_bracket(
        dest,
        width,
        height,
        dest_stride,
        BracketExtent,
        BracketColor,
        sizeof(BracketColor));

    m_image_mutex.unlock();
}

void RenderWidget::blit_tile(
    const Frame&    frame,
    const size_t    tile_x,
    const size_t    tile_y)
{
    m_image_mutex.lock();

    blit_tile_no_lock(frame, tile_x, tile_y);

    m_image_mutex.unlock();
}

void RenderWidget::blit_frame(
    const Frame&    frame)
{
    const CanvasProperties& frame_props = frame.image().properties();

    Tile float_tile_storage(
        frame_props.m_tile_width,
        frame_props.m_tile_height,
        frame_props.m_channel_count,
        PixelFormatFloat);

    Tile uint8_tile_storage(
        frame_props.m_tile_width,
        frame_props.m_tile_height,
        frame_props.m_channel_count,
        PixelFormatUInt8);

    m_image_mutex.lock();

    for (size_t ty = 0; ty < frame_props.m_tile_count_y; ++ty)
    {
        for (size_t tx = 0; tx < frame_props.m_tile_count_x; ++tx)
        {
            blit_tile_no_lock(
                frame,
                tx,
                ty,
                float_tile_storage.get_storage(),
                uint8_tile_storage.get_storage());
        }
    }

    m_image_mutex.unlock();
}

void RenderWidget::blit_tile_no_lock(
    const Frame&    frame,
    const size_t    tile_x,
    const size_t    tile_y,
    uint8*          float_tile_storage,
    uint8*          uint8_tile_storage)
{
    // Retrieve the source tile.
    const Tile& tile = frame.image().tile(tile_x, tile_y);

    // Convert the tile to 32-bit floating point.
    Tile fp_rgb_tile(
        tile,
        PixelFormatFloat,
        float_tile_storage);

    // Transform the tile to the color space of the frame.
    frame.transform_to_output_color_space(fp_rgb_tile);

    // Convert the tile to 8-bit RGB for display.
    static const size_t ShuffleTable[] = { 0, 1, 2, Pixel::SkipChannel };
    const Tile uint8_rgb_tile(
        fp_rgb_tile,
        PixelFormatUInt8,
        ShuffleTable,
        uint8_tile_storage);

    // Retrieve destination image information.
    const size_t image_width = static_cast<size_t>(m_image.width());
    const size_t image_height = static_cast<size_t>(m_image.height());
    const size_t dest_stride = static_cast<size_t>(m_image.bytesPerLine());

    // Compute the coordinates of the first destination pixel.
    const CanvasProperties& frame_props = frame.image().properties();
    const size_t x = tile_x * frame_props.m_tile_width;
    const size_t y = tile_y * frame_props.m_tile_height;

    // Clipping is not supported.
    assert(x < image_width);
    assert(y < image_height);
    assert(x + tile.get_width() <= image_width);
    assert(y + tile.get_height() <= image_height);

    // Get a pointer to the first destination pixel.
    uint8* dest = get_image_pointer(m_image, x, y);

    // Blit the tile to the destination image.
    NativeDrawing::blit(dest, dest_stride, uint8_rgb_tile);
}

void RenderWidget::paintEvent(QPaintEvent* event)
{
    m_image_mutex.lock();

    m_painter.begin(this);
    m_painter.drawImage(rect(), m_image);
    m_painter.end();

    m_image_mutex.unlock();
}

}   // namespace studio
}   // namespace appleseed
<|endoftext|>


<commit_before>/* rbOOmit: An implementation of the Certified Reduced Basis method. */
/* Copyright (C) 2009, 2010 David J. Knezevic */
/*     This file is part of rbOOmit. */

/* rbOOmit is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Lesser General Public */
/* License as published by the Free Software Foundation; either */
/* version 2.1 of the License, or (at your option) any later version. */

/* rbOOmit 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 */

//
Reduced Basis Example 1 - Certified Reduced Basis Method

// In this example problem we use the Certified Reduced Basis method
// to solve a steady convection-diffusion problem on the unit square.
// The reduced basis method relies on an expansion of the PDE in the
// form \sum_q=1^Q_a theta_a^q(\mu) * a^q(u,v) = \sum_q=1^Q_f theta_f^q(\mu) f^q(v)
// where theta_a, theta_f are parameter dependent functions and
// a^q, f^q are parameter independent operators (\mu denotes a parameter).

// We first attach the parameter dependent functions and paramater
// independent operators to the RBSystem. Then in Offline mode, a
// reduced basis space is generated and written out to the directory
// "offline_data". In Online mode, the reduced basis data in "offline_data"
// is read in and used to solve the reduced problem for the parameters
// specified in reduced_basis_ex1.in.

// We also attach four outputs to the system which are averages over certain
// subregions of the domain. In Online mode, we print out the values of these
// outputs as well as rigorous error bounds with respect to the output
// associated with the "truth" finite element discretization.

// C++ include files that we need
#include <iostream>
#include <algorithm>
#include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
#include <cmath>
#include <set>

// Basic include file needed for the mesh functionality.
#include "libmesh/libmesh.h"
#include "libmesh/mesh.h"
#include "libmesh/mesh_generation.h"
#include "libmesh/exodusII_io.h"
#include "libmesh/equation_systems.h"
#include "libmesh/dof_map.h"
#include "libmesh/getpot.h"
#include "libmesh/elem.h"

// local includes
#include "rb_classes.h"
#include "assembly.h"

// Bring in everything from the libMesh namespace
using namespace libMesh;

// The main program.
int main (int argc, char** argv)
{
  // Initialize libMesh.
  LibMeshInit init (argc, argv);

#if !defined(LIBMESH_HAVE_XDR)
  // We need XDR support to write out reduced bases
  libmesh_example_requires(false, "--enable-xdr");
#elif defined(LIBMESH_DEFAULT_SINGLE_PRECISION)
  // XDR binary support requires double precision
  libmesh_example_requires(false, "--disable-singleprecision");
#endif
  // FIXME: This example currently segfaults with Trilinos?  It works
  // with PETSc and Eigen sparse linear solvers though.
  libmesh_example_requires(libMesh::default_solver_package() != TRILINOS_SOLVERS, "--enable-petsc");

  // Skip this 2D example if libMesh was compiled as 1D-only.
  libmesh_example_requires(2 <= LIBMESH_DIM, "2D support");

  // Parse the input file (reduced_basis_ex1.in) using GetPot
  std::string parameters_filename = "reduced_basis_ex1.in";
  GetPot infile(parameters_filename);

  unsigned int n_elem = infile("n_elem", 1);       // Determines the number of elements in the "truth" mesh
  const unsigned int dim = 2;                      // The number of spatial dimensions

  bool store_basis_functions = infile("store_basis_functions", true); // Do we write the RB basis functions to disk?

  // Read the "online_mode" flag from the command line
  GetPot command_line (argc, argv);
  int online_mode = 0;
  if ( command_line.search(1, "-online_mode") )
    online_mode = command_line.next(online_mode);

  // Build a mesh on the default MPI communicator.
  Mesh mesh (init.comm(), dim);
  MeshTools::Generation::build_square (mesh,
                                       n_elem, n_elem,
                                       0., 1.,
                                       0., 1.,
                                       QUAD4);

  // Create an equation systems object.
  EquationSystems equation_systems (mesh);

  // We override RBConstruction with SimpleRBConstruction in order to
  // specialize a few functions for this particular problem.
  SimpleRBConstruction & rb_con =
    equation_systems.add_system<SimpleRBConstruction> ("RBConvectionDiffusion");

  // Initialize the data structures for the equation system.
  equation_systems.init ();

  // Print out some information about the "truth" discretization
  equation_systems.print_info();
  mesh.print_info();

  // Build a new RBEvaluation object which will be used to perform
  // Reduced Basis calculations. This is required in both the
  // "Offline" and "Online" stages.
  SimpleRBEvaluation rb_eval(mesh.comm());

  // We need to give the RBConstruction object a pointer to
  // our RBEvaluation object
  rb_con.set_rb_evaluation(rb_eval);

  if(!online_mode) // Perform the Offline stage of the RB method
    {
      // Read in the data that defines this problem from the specified text file
      rb_con.process_parameters_file(parameters_filename);

      // Print out info that describes the current setup of rb_con
      rb_con.print_info();

      // Prepare rb_con for the Construction stage of the RB method.
      // This sets up the necessary data structures and performs
      // initial assembly of the "truth" affine expansion of the PDE.
      rb_con.initialize_rb_construction();

      // Compute the reduced basis space by computing "snapshots", i.e.
      // "truth" solves, at well-chosen parameter values and employing
      // these snapshots as basis functions.
      rb_con.train_reduced_basis();

      // Write out the data that will subsequently be required for the Evaluation stage
      rb_con.get_rb_evaluation().write_offline_data_to_files();

      // If requested, write out the RB basis functions for visualization purposes
      if(store_basis_functions)
        {
          // Write out the basis functions
          rb_con.get_rb_evaluation().write_out_basis_functions(rb_con);
        }

      // Basis functions should be orthonormal, so
      // print out the inner products to check this
      rb_con.print_basis_function_orthogonality();
    }
  else // Perform the Online stage of the RB method
    {
      // Read in the reduced basis data
      rb_eval.read_offline_data_from_files();

      // Read in online_N and initialize online parameters
      unsigned int online_N = infile("online_N",1);
      Real online_x_vel = infile("online_x_vel", 0.);
      Real online_y_vel = infile("online_y_vel", 0.);
      RBParameters online_mu;
      online_mu.set_value("x_vel", online_x_vel);
      online_mu.set_value("y_vel", online_y_vel);
      rb_eval.set_parameters(online_mu);
      rb_eval.print_parameters();

      // Now do the Online solve using the precomputed reduced basis
      rb_eval.rb_solve(online_N);

      // Print out outputs as well as the corresponding output error bounds.
      std::cout << "output 1, value = " << rb_eval.RB_outputs[0]
                << ", bound = " << rb_eval.RB_output_error_bounds[0]
                << std::endl;
      std::cout << "output 2, value = " << rb_eval.RB_outputs[1]
                << ", bound = " << rb_eval.RB_output_error_bounds[1]
                << std::endl;
      std::cout << "output 3, value = " << rb_eval.RB_outputs[2]
                << ", bound = " << rb_eval.RB_output_error_bounds[2]
                << std::endl;
      std::cout << "output 4, value = " << rb_eval.RB_outputs[3]
                << ", bound = " << rb_eval.RB_output_error_bounds[3]
                << std::endl << std::endl;

      if(store_basis_functions)
        {
          // Read in the basis functions
          rb_eval.read_in_basis_functions(rb_con);

          // Plot the solution
          rb_con.load_rb_solution();
#ifdef LIBMESH_HAVE_EXODUS_API
          ExodusII_IO(mesh).write_equation_systems ("RB_sol.e",equation_systems);
#endif

          // Plot the first basis function that was generated from the train_reduced_basis
          // call in the Offline stage
          rb_con.load_basis_function(0);
#ifdef LIBMESH_HAVE_EXODUS_API
          ExodusII_IO(mesh).write_equation_systems ("bf0.e",equation_systems);
#endif
        }
    }

  return 0;
}
<commit_msg>Require PETSc.<commit_after>/* rbOOmit: An implementation of the Certified Reduced Basis method. */
/* Copyright (C) 2009, 2010 David J. Knezevic */
/*     This file is part of rbOOmit. */

/* rbOOmit is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Lesser General Public */
/* License as published by the Free Software Foundation; either */
/* version 2.1 of the License, or (at your option) any later version. */

/* rbOOmit 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 */

//
Reduced Basis Example 1 - Certified Reduced Basis Method

// In this example problem we use the Certified Reduced Basis method
// to solve a steady convection-diffusion problem on the unit square.
// The reduced basis method relies on an expansion of the PDE in the
// form \sum_q=1^Q_a theta_a^q(\mu) * a^q(u,v) = \sum_q=1^Q_f theta_f^q(\mu) f^q(v)
// where theta_a, theta_f are parameter dependent functions and
// a^q, f^q are parameter independent operators (\mu denotes a parameter).

// We first attach the parameter dependent functions and paramater
// independent operators to the RBSystem. Then in Offline mode, a
// reduced basis space is generated and written out to the directory
// "offline_data". In Online mode, the reduced basis data in "offline_data"
// is read in and used to solve the reduced problem for the parameters
// specified in reduced_basis_ex1.in.

// We also attach four outputs to the system which are averages over certain
// subregions of the domain. In Online mode, we print out the values of these
// outputs as well as rigorous error bounds with respect to the output
// associated with the "truth" finite element discretization.

// C++ include files that we need
#include <iostream>
#include <algorithm>
#include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
#include <cmath>
#include <set>

// Basic include file needed for the mesh functionality.
#include "libmesh/libmesh.h"
#include "libmesh/mesh.h"
#include "libmesh/mesh_generation.h"
#include "libmesh/exodusII_io.h"
#include "libmesh/equation_systems.h"
#include "libmesh/dof_map.h"
#include "libmesh/getpot.h"
#include "libmesh/elem.h"

// local includes
#include "rb_classes.h"
#include "assembly.h"

// Bring in everything from the libMesh namespace
using namespace libMesh;

// The main program.
int main (int argc, char** argv)
{
  // Initialize libMesh.
  LibMeshInit init (argc, argv);

#if !defined(LIBMESH_HAVE_XDR)
  // We need XDR support to write out reduced bases
  libmesh_example_requires(false, "--enable-xdr");
#elif defined(LIBMESH_DEFAULT_SINGLE_PRECISION)
  // XDR binary support requires double precision
  libmesh_example_requires(false, "--disable-singleprecision");
#endif
  // FIXME: This example currently segfaults with Trilinos?
  // with Eigen sparse solvers, libMesh::EigenSparseLinearSolver<double>::get_converged_reason()
  // aborts with not implemented
  libmesh_example_requires(libMesh::default_solver_package() == PETSC_SOLVERS, "--enable-petsc");

  // Skip this 2D example if libMesh was compiled as 1D-only.
  libmesh_example_requires(2 <= LIBMESH_DIM, "2D support");

  // Parse the input file (reduced_basis_ex1.in) using GetPot
  std::string parameters_filename = "reduced_basis_ex1.in";
  GetPot infile(parameters_filename);

  unsigned int n_elem = infile("n_elem", 1);       // Determines the number of elements in the "truth" mesh
  const unsigned int dim = 2;                      // The number of spatial dimensions

  bool store_basis_functions = infile("store_basis_functions", true); // Do we write the RB basis functions to disk?

  // Read the "online_mode" flag from the command line
  GetPot command_line (argc, argv);
  int online_mode = 0;
  if ( command_line.search(1, "-online_mode") )
    online_mode = command_line.next(online_mode);

  // Build a mesh on the default MPI communicator.
  Mesh mesh (init.comm(), dim);
  MeshTools::Generation::build_square (mesh,
                                       n_elem, n_elem,
                                       0., 1.,
                                       0., 1.,
                                       QUAD4);

  // Create an equation systems object.
  EquationSystems equation_systems (mesh);

  // We override RBConstruction with SimpleRBConstruction in order to
  // specialize a few functions for this particular problem.
  SimpleRBConstruction & rb_con =
    equation_systems.add_system<SimpleRBConstruction> ("RBConvectionDiffusion");

  // Initialize the data structures for the equation system.
  equation_systems.init ();

  // Print out some information about the "truth" discretization
  equation_systems.print_info();
  mesh.print_info();

  // Build a new RBEvaluation object which will be used to perform
  // Reduced Basis calculations. This is required in both the
  // "Offline" and "Online" stages.
  SimpleRBEvaluation rb_eval(mesh.comm());

  // We need to give the RBConstruction object a pointer to
  // our RBEvaluation object
  rb_con.set_rb_evaluation(rb_eval);

  if(!online_mode) // Perform the Offline stage of the RB method
    {
      // Read in the data that defines this problem from the specified text file
      rb_con.process_parameters_file(parameters_filename);

      // Print out info that describes the current setup of rb_con
      rb_con.print_info();

      // Prepare rb_con for the Construction stage of the RB method.
      // This sets up the necessary data structures and performs
      // initial assembly of the "truth" affine expansion of the PDE.
      rb_con.initialize_rb_construction();

      // Compute the reduced basis space by computing "snapshots", i.e.
      // "truth" solves, at well-chosen parameter values and employing
      // these snapshots as basis functions.
      rb_con.train_reduced_basis();

      // Write out the data that will subsequently be required for the Evaluation stage
      rb_con.get_rb_evaluation().write_offline_data_to_files();

      // If requested, write out the RB basis functions for visualization purposes
      if(store_basis_functions)
        {
          // Write out the basis functions
          rb_con.get_rb_evaluation().write_out_basis_functions(rb_con);
        }

      // Basis functions should be orthonormal, so
      // print out the inner products to check this
      rb_con.print_basis_function_orthogonality();
    }
  else // Perform the Online stage of the RB method
    {
      // Read in the reduced basis data
      rb_eval.read_offline_data_from_files();

      // Read in online_N and initialize online parameters
      unsigned int online_N = infile("online_N",1);
      Real online_x_vel = infile("online_x_vel", 0.);
      Real online_y_vel = infile("online_y_vel", 0.);
      RBParameters online_mu;
      online_mu.set_value("x_vel", online_x_vel);
      online_mu.set_value("y_vel", online_y_vel);
      rb_eval.set_parameters(online_mu);
      rb_eval.print_parameters();

      // Now do the Online solve using the precomputed reduced basis
      rb_eval.rb_solve(online_N);

      // Print out outputs as well as the corresponding output error bounds.
      std::cout << "output 1, value = " << rb_eval.RB_outputs[0]
                << ", bound = " << rb_eval.RB_output_error_bounds[0]
                << std::endl;
      std::cout << "output 2, value = " << rb_eval.RB_outputs[1]
                << ", bound = " << rb_eval.RB_output_error_bounds[1]
                << std::endl;
      std::cout << "output 3, value = " << rb_eval.RB_outputs[2]
                << ", bound = " << rb_eval.RB_output_error_bounds[2]
                << std::endl;
      std::cout << "output 4, value = " << rb_eval.RB_outputs[3]
                << ", bound = " << rb_eval.RB_output_error_bounds[3]
                << std::endl << std::endl;

      if(store_basis_functions)
        {
          // Read in the basis functions
          rb_eval.read_in_basis_functions(rb_con);

          // Plot the solution
          rb_con.load_rb_solution();
#ifdef LIBMESH_HAVE_EXODUS_API
          ExodusII_IO(mesh).write_equation_systems ("RB_sol.e",equation_systems);
#endif

          // Plot the first basis function that was generated from the train_reduced_basis
          // call in the Offline stage
          rb_con.load_basis_function(0);
#ifdef LIBMESH_HAVE_EXODUS_API
          ExodusII_IO(mesh).write_equation_systems ("bf0.e",equation_systems);
#endif
        }
    }

  return 0;
}
<|endoftext|>


<commit_before>/* rbOOmit: An implementation of the Certified Reduced Basis method. */
/* Copyright (C) 2009, 2010 David J. Knezevic */
/*     This file is part of rbOOmit. */

/* rbOOmit is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Lesser General Public */
/* License as published by the Free Software Foundation; either */
/* version 2.1 of the License, or (at your option) any later version. */

/* rbOOmit 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 */

//
Reduced Basis Example 4 - Empirical Interpolation Method

// In this example problem we develop a reduced basis approximation for a parametrized
// PDE that has "non-affine" parameter dependence. This requires the use of the
// Empirical Interpolation Method (EIM).
//
// We first use EIM to construct an affine approximation to the non-affine term,
// which is a parametrized function that is a Gaussian with "center" defined
// by the two parameters (mu_1,mu_2) \in [-1,1]^2. We then employ this EIM
// approximation in order to generate a reduced basis approximation for the
// parametrized PDE: -0.05 * Laplacian(u) = f(mu_1,mu_2), with zero Dirichlet
// boundary conditions.

// Basic include file needed for the mesh functionality.
#include "libmesh/libmesh.h"
#include "libmesh/mesh.h"
#include "libmesh/mesh_generation.h"
#include "libmesh/equation_systems.h"
#include "libmesh/exodusII_io.h"
#include "libmesh/getpot.h"

#include "eim_classes.h"
#include "rb_classes.h"

using namespace libMesh;

int main (int argc, char** argv)
{
  // Initialize libMesh.
  LibMeshInit init (argc, argv);

#if !defined(LIBMESH_HAVE_XDR)
  // We need XDR support to write out reduced bases
  libmesh_example_requires(false, "--enable-xdr");
#elif defined(LIBMESH_DEFAULT_SINGLE_PRECISION)
  // XDR binary support requires double precision
  libmesh_example_requires(false, "--disable-singleprecision");
#endif

  // Skip this 2D example if libMesh was compiled as 1D-only.
  libmesh_example_requires(2 <= LIBMESH_DIM, "2D support");

  // Define the names of the input files we will read the problem properties from
  std::string eim_parameters = "eim.in";
  std::string rb_parameters  = "rb.in";
  std::string main_parameters = "reduced_basis_ex4.in";
  GetPot infile(main_parameters);

  unsigned int n_elem = infile("n_elem", 1);       // Determines the number of elements in the "truth" mesh
  const unsigned int dim = 2;                      // The number of spatial dimensions
  bool store_basis_functions = infile("store_basis_functions", false); // Do we write out basis functions?

  // Read the "online_mode" flag from the command line
  GetPot command_line (argc, argv);
  int online_mode = 0;
  if ( command_line.search(1, "-online_mode") )
    online_mode = command_line.next(online_mode);

  // Create a mesh (just a simple square) on the default MPI
  // communicator.  We currently have to create a SerialMesh here due
  // to a reduced_basis regression with ParallelMesh
  SerialMesh mesh (init.comm(), dim);
  MeshTools::Generation::build_square (mesh,
                                       n_elem, n_elem,
                                       -1., 1.,
                                       -1., 1.,
                                       QUAD4);

  // Initialize the EquationSystems object for this mesh and attach
  // the EIM and RB Construction objects
  EquationSystems equation_systems (mesh);

  SimpleEIMConstruction & eim_construction =
    equation_systems.add_system<SimpleEIMConstruction> ("EIM");
  SimpleRBConstruction & rb_construction =
    equation_systems.add_system<SimpleRBConstruction> ("RB");

  // Initialize the data structures for the equation system.
  equation_systems.init ();

  // Print out some information about the "truth" discretization
  mesh.print_info();
  equation_systems.print_info();

  // Initialize the standard RBEvaluation object
  SimpleRBEvaluation rb_eval(mesh.comm());

  // Initialize the EIM RBEvaluation object
  SimpleEIMEvaluation eim_rb_eval(mesh.comm());

  // Set the rb_eval objects for the RBConstructions
  eim_construction.set_rb_evaluation(eim_rb_eval);
  rb_construction.set_rb_evaluation(rb_eval);

  if(!online_mode)
    {
      // Read data from input file and print state
      eim_construction.process_parameters_file(eim_parameters);
      eim_construction.print_info();

      // Perform the EIM Greedy and write out the data
      eim_construction.initialize_rb_construction();
      eim_construction.train_reduced_basis();
      eim_construction.get_rb_evaluation().write_offline_data_to_files("eim_data");

      // Read data from input file and print state
      rb_construction.process_parameters_file(rb_parameters);

      // attach the EIM theta objects to the RBConstruction and RBEvaluation objects
      eim_rb_eval.initialize_eim_theta_objects();
      rb_eval.get_rb_theta_expansion().attach_multiple_F_theta(eim_rb_eval.get_eim_theta_objects());

      // attach the EIM assembly objects to the RBConstruction object
      eim_construction.initialize_eim_assembly_objects();
      rb_construction.get_rb_assembly_expansion().attach_multiple_F_assembly(eim_construction.get_eim_assembly_objects());

      // Print out the state of rb_construction now that the EIM objects have been attached
      rb_construction.print_info();

      // Need to initialize _after_ EIM greedy so that
      // the system knows how many affine terms there are
      rb_construction.initialize_rb_construction();
      rb_construction.train_reduced_basis();
      rb_construction.get_rb_evaluation().write_offline_data_to_files("rb_data");

      // Write out the basis functions, if requested
      if(store_basis_functions)
        {
          // Write out the basis functions
          eim_construction.get_rb_evaluation().write_out_basis_functions(eim_construction,"eim_data");
          rb_construction.get_rb_evaluation().write_out_basis_functions(rb_construction,"rb_data");
        }
    }
  else
    {
      eim_rb_eval.read_offline_data_from_files("eim_data");

      // attach the EIM theta objects to rb_eval objects
      eim_rb_eval.initialize_eim_theta_objects();
      rb_eval.get_rb_theta_expansion().attach_multiple_F_theta(eim_rb_eval.get_eim_theta_objects());

      // Read in the offline data for rb_eval
      rb_eval.read_offline_data_from_files("rb_data");

      // Get the parameters at which we will do a reduced basis solve
      Real online_center_x = infile("online_center_x", 0.);
      Real online_center_y = infile("online_center_y", 0.);
      RBParameters online_mu;
      online_mu.set_value("center_x", online_center_x);
      online_mu.set_value("center_y", online_center_y);
      rb_eval.set_parameters(online_mu);
      rb_eval.print_parameters();
      rb_eval.rb_solve( rb_eval.get_n_basis_functions() );

      // plot the solution, if requested
      if(store_basis_functions)
        {
          // read in the data from files
          eim_rb_eval.read_in_basis_functions(eim_construction,"eim_data");
          rb_eval.read_in_basis_functions(rb_construction,"rb_data");

          eim_construction.load_rb_solution();
          rb_construction.load_rb_solution();
#ifdef LIBMESH_HAVE_EXODUS_API
          ExodusII_IO(mesh).write_equation_systems("RB_sol.e",equation_systems);
#endif
        }
    }

}
<commit_msg>require PETSc<commit_after>/* rbOOmit: An implementation of the Certified Reduced Basis method. */
/* Copyright (C) 2009, 2010 David J. Knezevic */
/*     This file is part of rbOOmit. */

/* rbOOmit is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Lesser General Public */
/* License as published by the Free Software Foundation; either */
/* version 2.1 of the License, or (at your option) any later version. */

/* rbOOmit 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 */

//
Reduced Basis Example 4 - Empirical Interpolation Method

// In this example problem we develop a reduced basis approximation for a parametrized
// PDE that has "non-affine" parameter dependence. This requires the use of the
// Empirical Interpolation Method (EIM).
//
// We first use EIM to construct an affine approximation to the non-affine term,
// which is a parametrized function that is a Gaussian with "center" defined
// by the two parameters (mu_1,mu_2) \in [-1,1]^2. We then employ this EIM
// approximation in order to generate a reduced basis approximation for the
// parametrized PDE: -0.05 * Laplacian(u) = f(mu_1,mu_2), with zero Dirichlet
// boundary conditions.

// Basic include file needed for the mesh functionality.
#include "libmesh/libmesh.h"
#include "libmesh/mesh.h"
#include "libmesh/mesh_generation.h"
#include "libmesh/equation_systems.h"
#include "libmesh/exodusII_io.h"
#include "libmesh/getpot.h"

#include "eim_classes.h"
#include "rb_classes.h"

using namespace libMesh;

int main (int argc, char** argv)
{
  // Initialize libMesh.
  LibMeshInit init (argc, argv);

#if !defined(LIBMESH_HAVE_XDR)
  // We need XDR support to write out reduced bases
  libmesh_example_requires(false, "--enable-xdr");
#elif defined(LIBMESH_DEFAULT_SINGLE_PRECISION)
  // XDR binary support requires double precision
  libmesh_example_requires(false, "--disable-singleprecision");
#endif
  // FIXME: This example currently segfaults with Trilinos?
  // with Eigen sparse solvers, libMesh::EigenSparseLinearSolver<double>::get_converged_reason()
  // aborts with not implemented
  libmesh_example_requires(libMesh::default_solver_package() == PETSC_SOLVERS, "--enable-petsc");

  // Skip this 2D example if libMesh was compiled as 1D-only.
  libmesh_example_requires(2 <= LIBMESH_DIM, "2D support");

  // Define the names of the input files we will read the problem properties from
  std::string eim_parameters = "eim.in";
  std::string rb_parameters  = "rb.in";
  std::string main_parameters = "reduced_basis_ex4.in";
  GetPot infile(main_parameters);

  unsigned int n_elem = infile("n_elem", 1);       // Determines the number of elements in the "truth" mesh
  const unsigned int dim = 2;                      // The number of spatial dimensions
  bool store_basis_functions = infile("store_basis_functions", false); // Do we write out basis functions?

  // Read the "online_mode" flag from the command line
  GetPot command_line (argc, argv);
  int online_mode = 0;
  if ( command_line.search(1, "-online_mode") )
    online_mode = command_line.next(online_mode);

  // Create a mesh (just a simple square) on the default MPI
  // communicator.  We currently have to create a SerialMesh here due
  // to a reduced_basis regression with ParallelMesh
  SerialMesh mesh (init.comm(), dim);
  MeshTools::Generation::build_square (mesh,
                                       n_elem, n_elem,
                                       -1., 1.,
                                       -1., 1.,
                                       QUAD4);

  // Initialize the EquationSystems object for this mesh and attach
  // the EIM and RB Construction objects
  EquationSystems equation_systems (mesh);

  SimpleEIMConstruction & eim_construction =
    equation_systems.add_system<SimpleEIMConstruction> ("EIM");
  SimpleRBConstruction & rb_construction =
    equation_systems.add_system<SimpleRBConstruction> ("RB");

  // Initialize the data structures for the equation system.
  equation_systems.init ();

  // Print out some information about the "truth" discretization
  mesh.print_info();
  equation_systems.print_info();

  // Initialize the standard RBEvaluation object
  SimpleRBEvaluation rb_eval(mesh.comm());

  // Initialize the EIM RBEvaluation object
  SimpleEIMEvaluation eim_rb_eval(mesh.comm());

  // Set the rb_eval objects for the RBConstructions
  eim_construction.set_rb_evaluation(eim_rb_eval);
  rb_construction.set_rb_evaluation(rb_eval);

  if(!online_mode)
    {
      // Read data from input file and print state
      eim_construction.process_parameters_file(eim_parameters);
      eim_construction.print_info();

      // Perform the EIM Greedy and write out the data
      eim_construction.initialize_rb_construction();
      eim_construction.train_reduced_basis();
      eim_construction.get_rb_evaluation().write_offline_data_to_files("eim_data");

      // Read data from input file and print state
      rb_construction.process_parameters_file(rb_parameters);

      // attach the EIM theta objects to the RBConstruction and RBEvaluation objects
      eim_rb_eval.initialize_eim_theta_objects();
      rb_eval.get_rb_theta_expansion().attach_multiple_F_theta(eim_rb_eval.get_eim_theta_objects());

      // attach the EIM assembly objects to the RBConstruction object
      eim_construction.initialize_eim_assembly_objects();
      rb_construction.get_rb_assembly_expansion().attach_multiple_F_assembly(eim_construction.get_eim_assembly_objects());

      // Print out the state of rb_construction now that the EIM objects have been attached
      rb_construction.print_info();

      // Need to initialize _after_ EIM greedy so that
      // the system knows how many affine terms there are
      rb_construction.initialize_rb_construction();
      rb_construction.train_reduced_basis();
      rb_construction.get_rb_evaluation().write_offline_data_to_files("rb_data");

      // Write out the basis functions, if requested
      if(store_basis_functions)
        {
          // Write out the basis functions
          eim_construction.get_rb_evaluation().write_out_basis_functions(eim_construction,"eim_data");
          rb_construction.get_rb_evaluation().write_out_basis_functions(rb_construction,"rb_data");
        }
    }
  else
    {
      eim_rb_eval.read_offline_data_from_files("eim_data");

      // attach the EIM theta objects to rb_eval objects
      eim_rb_eval.initialize_eim_theta_objects();
      rb_eval.get_rb_theta_expansion().attach_multiple_F_theta(eim_rb_eval.get_eim_theta_objects());

      // Read in the offline data for rb_eval
      rb_eval.read_offline_data_from_files("rb_data");

      // Get the parameters at which we will do a reduced basis solve
      Real online_center_x = infile("online_center_x", 0.);
      Real online_center_y = infile("online_center_y", 0.);
      RBParameters online_mu;
      online_mu.set_value("center_x", online_center_x);
      online_mu.set_value("center_y", online_center_y);
      rb_eval.set_parameters(online_mu);
      rb_eval.print_parameters();
      rb_eval.rb_solve( rb_eval.get_n_basis_functions() );

      // plot the solution, if requested
      if(store_basis_functions)
        {
          // read in the data from files
          eim_rb_eval.read_in_basis_functions(eim_construction,"eim_data");
          rb_eval.read_in_basis_functions(rb_construction,"rb_data");

          eim_construction.load_rb_solution();
          rb_construction.load_rb_solution();
#ifdef LIBMESH_HAVE_EXODUS_API
          ExodusII_IO(mesh).write_equation_systems("RB_sol.e",equation_systems);
#endif
        }
    }

}
<|endoftext|>


<commit_before>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#if defined(WITH_CUDA_LINEAR_ALGEBRA)

#include <cusolverDnManager.hpp>
#include <platform.hpp>

#include <stdexcept>
#include <string>
#include <iostream>
#include <boost/scoped_ptr.hpp>

namespace cusolver {

    const char *errorString(cusolverStatus_t err)
    {
        switch(err) {
        case    CUSOLVER_STATUS_SUCCESS                     :   return "CUSOLVER_STATUS_SUCCESS"                    ;
        case    CUSOLVER_STATUS_NOT_INITIALIZED             :   return "CUSOLVER_STATUS_NOT_INITIALIZED"            ;
        case    CUSOLVER_STATUS_ALLOC_FAILED                :   return "CUSOLVER_STATUS_ALLOC_FAILED"               ;
        case    CUSOLVER_STATUS_INVALID_VALUE               :   return "CUSOLVER_STATUS_INVALID_VALUE"              ;
        case    CUSOLVER_STATUS_ARCH_MISMATCH               :   return "CUSOLVER_STATUS_ARCH_MISMATCH"              ;
        case    CUSOLVER_STATUS_MAPPING_ERROR               :   return "CUSOLVER_STATUS_MAPPING_ERROR"              ;
        case    CUSOLVER_STATUS_EXECUTION_FAILED            :   return "CUSOLVER_STATUS_EXECUTION_FAILED"           ;
        case    CUSOLVER_STATUS_INTERNAL_ERROR              :   return "CUSOLVER_STATUS_INTERNAL_ERROR"             ;
        case    CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED   :   return "CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED"  ;
        case    CUSOLVER_STATUS_NOT_SUPPORTED               :   return "CUSOLVER_STATUS_NOT_SUPPORTED"              ;
        case    CUSOLVER_STATUS_ZERO_PIVOT                  :   return "CUSOLVER_STATUS_ZERO_PIVOT"                 ;
        case    CUSOLVER_STATUS_INVALID_LICENSE             :   return "CUSOLVER_STATUS_INVALID_LICENSE"            ;
        default                                             :   return "UNKNOWN";
        }
    }

//RAII class around the cusolver Handle
    class cusolverDnHandle
    {
        cusolverDnHandle_t handle;
    public:

        cusolverDnHandle()
            : handle(0)
        {
            CUSOLVER_CHECK(cusolverDnCreate(&handle));
        }

        ~cusolverDnHandle()
        {
            cusolverDnDestroy(handle);
        }

        cusolverDnHandle_t get() const
        {
            return handle;
        }
    };

    cusolverDnHandle_t getDnHandle()
    {
        using boost::scoped_ptr;
        static scoped_ptr<cusolverDnHandle> handle[cuda::DeviceManager::MAX_DEVICES];

        int id = cuda::getActiveDeviceId();

        if(!handle[id]) {
            handle[id].reset(new cusolverDnHandle());
        }

        return handle[id]->get();
    }

}

#endif
<commit_msg>Set the correct stream for cusolver manager<commit_after>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#if defined(WITH_CUDA_LINEAR_ALGEBRA)

#include <cusolverDnManager.hpp>
#include <platform.hpp>

#include <stdexcept>
#include <string>
#include <iostream>
#include <boost/scoped_ptr.hpp>

namespace cusolver {

    const char *errorString(cusolverStatus_t err)
    {
        switch(err) {
        case    CUSOLVER_STATUS_SUCCESS                     :   return "CUSOLVER_STATUS_SUCCESS"                    ;
        case    CUSOLVER_STATUS_NOT_INITIALIZED             :   return "CUSOLVER_STATUS_NOT_INITIALIZED"            ;
        case    CUSOLVER_STATUS_ALLOC_FAILED                :   return "CUSOLVER_STATUS_ALLOC_FAILED"               ;
        case    CUSOLVER_STATUS_INVALID_VALUE               :   return "CUSOLVER_STATUS_INVALID_VALUE"              ;
        case    CUSOLVER_STATUS_ARCH_MISMATCH               :   return "CUSOLVER_STATUS_ARCH_MISMATCH"              ;
        case    CUSOLVER_STATUS_MAPPING_ERROR               :   return "CUSOLVER_STATUS_MAPPING_ERROR"              ;
        case    CUSOLVER_STATUS_EXECUTION_FAILED            :   return "CUSOLVER_STATUS_EXECUTION_FAILED"           ;
        case    CUSOLVER_STATUS_INTERNAL_ERROR              :   return "CUSOLVER_STATUS_INTERNAL_ERROR"             ;
        case    CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED   :   return "CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED"  ;
        case    CUSOLVER_STATUS_NOT_SUPPORTED               :   return "CUSOLVER_STATUS_NOT_SUPPORTED"              ;
        case    CUSOLVER_STATUS_ZERO_PIVOT                  :   return "CUSOLVER_STATUS_ZERO_PIVOT"                 ;
        case    CUSOLVER_STATUS_INVALID_LICENSE             :   return "CUSOLVER_STATUS_INVALID_LICENSE"            ;
        default                                             :   return "UNKNOWN";
        }
    }

//RAII class around the cusolver Handle
    class cusolverDnHandle
    {
        cusolverDnHandle_t handle;
    public:

        cusolverDnHandle()
            : handle(0)
        {
            CUSOLVER_CHECK(cusolverDnCreate(&handle));
            CUSOLVER_CHECK(cusolverDnSetStream(handle, cuda::getStream(cuda::getActiveDeviceId())));
        }

        ~cusolverDnHandle()
        {
            cusolverDnDestroy(handle);
        }

        cusolverDnHandle_t get() const
        {
            return handle;
        }
    };

    cusolverDnHandle_t getDnHandle()
    {
        using boost::scoped_ptr;
        static scoped_ptr<cusolverDnHandle> handle[cuda::DeviceManager::MAX_DEVICES];

        int id = cuda::getActiveDeviceId();

        if(!handle[id]) {
            handle[id].reset(new cusolverDnHandle());
        }

        return handle[id]->get();
    }

}

#endif
<|endoftext|>