<commit_before>#define CATCH_CONFIG_MAIN
#include "../../vendor/catch/catch.hpp"

#include "thread_utility.hpp"

TEST_CASE("initialize") {
  krbn::thread_utility::register_main_thread();
}

TEST_CASE("timer") {
  std::cout << "timer" << std::endl;

  {
    size_t count = 0;

    krbn::thread_utility::timer timer(
        std::chrono::milliseconds(100),
        false,
        [&] {
          ++count;
        });

    std::this_thread::sleep_for(std::chrono::milliseconds(500));

    timer.cancel();

    REQUIRE(count == 1);
  }

  // Wait

  {
    size_t count = 0;
    size_t wait_count = 0;

    krbn::thread_utility::timer timer(
        std::chrono::milliseconds(500),
        false,
        [&] {
          ++count;
        });

    auto thread = std::thread([&] {
      for (int i = 0; i < 5; ++i) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));

        ++wait_count;
      }
    });

    timer.wait();

    REQUIRE(count == 1);
    REQUIRE(wait_count > 1);

    thread.join();
  }

  // Cancel (1)

  {
    size_t count = 0;

    krbn::thread_utility::timer timer(
        std::chrono::milliseconds(500),
        false,
        [&] {
          ++count;
        });

    timer.cancel();

    std::this_thread::sleep_for(std::chrono::milliseconds(1000));

    REQUIRE(count == 0);
  }

  // Cancel (2)

  {
    size_t count = 0;

    {
      krbn::thread_utility::timer timer(
          std::chrono::milliseconds(50000),
          false,
          [&] {
            ++count;
          });
    }
  }

  // Cancel while wait

  {
    size_t count = 0;

    krbn::thread_utility::timer timer(
        std::chrono::milliseconds(500),
        false,
        [&] {
          ++count;
        });

    auto thread = std::thread([&] {
      std::this_thread::sleep_for(std::chrono::milliseconds(100));

      timer.cancel();
    });

    timer.wait();

    REQUIRE(count == 0);

    thread.join();
  }
}

TEST_CASE("timer.repeats") {
  std::cout << "timer.repeats" << std::endl;

  // Cancel while wait

  {
    size_t count = 0;

    krbn::thread_utility::timer timer(
        std::chrono::milliseconds(100),
        true,
        [&] {
          ++count;
        });

    std::this_thread::sleep_for(std::chrono::milliseconds(500));

    timer.cancel();
    timer.wait();

    REQUIRE(count >= 2);
    REQUIRE(count <= 10);
  }

  {
    size_t count = 0;

    // Call `cancel` in `~timer`.

    {
      krbn::thread_utility::timer timer(
          std::chrono::milliseconds(100),
          true,
          [&] {
            ++count;
          });

      std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }

    REQUIRE(count >= 2);
    REQUIRE(count <= 10);
  }

  {
    size_t count = 0;

    // `unset_repeats`

    {
      krbn::thread_utility::timer timer(
          std::chrono::milliseconds(100),
          true,
          [&] {
            ++count;
            if (count == 2) {
              timer.unset_repeats();
            }
          });

      std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }

    REQUIRE(count == 2);
  }
}

TEST_CASE("timer.repeats.interval") {
  std::cout << "timer.repeats.interval" << std::endl;

  {
    size_t count = 0;

    krbn::thread_utility::timer timer(
        [](auto&& count) {
          if (count == 0) {
            return std::chrono::milliseconds(0);
          } else {
            return std::chrono::milliseconds(500);
          }
        },
        true,
        [&] {
          ++count;
        });

    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    REQUIRE(count == 1);

    std::this_thread::sleep_for(std::chrono::milliseconds(1000));

    REQUIRE(count > 1);
  }
}

TEST_CASE("queue") {
  std::cout << "queue" << std::endl;

  {
    size_t count = 0;

    krbn::thread_utility::queue queue;

    for (int i = 0; i < 10000; ++i) {
      queue.push_back([&count, i] {
        ++count;
        if (i % 1000 == 0) {
          std::this_thread::sleep_for(std::chrono::milliseconds(50));
        }
      });
    }

    REQUIRE(count < 10000);

    std::this_thread::sleep_for(std::chrono::milliseconds(1000));

    REQUIRE(count == 10000);
  }

  // Run queued functions in the destructor.

  {
    size_t count = 0;

    {
      krbn::thread_utility::queue queue;

      for (int i = 0; i < 10000; ++i) {
        queue.push_back([&count, i] {
          ++count;
          if (i % 1000 == 0) {
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
          }
        });
      }
    }

    REQUIRE(count == 10000);
  }
}
<commit_msg>update tests<commit_after>#define CATCH_CONFIG_MAIN
#include "../../vendor/catch/catch.hpp"

#include "thread_utility.hpp"

TEST_CASE("initialize") {
  krbn::thread_utility::register_main_thread();
}

TEST_CASE("timer") {
  std::cout << "timer" << std::endl;

  {
    size_t count = 0;

    krbn::thread_utility::timer timer(
        std::chrono::milliseconds(100),
        false,
        [&] {
          ++count;
        });

    std::this_thread::sleep_for(std::chrono::milliseconds(500));

    timer.cancel();

    REQUIRE(count == 1);
  }

  // Wait

  {
    size_t count = 0;
    size_t wait_count = 0;

    krbn::thread_utility::timer timer(
        std::chrono::milliseconds(500),
        false,
        [&] {
          ++count;
        });

    auto thread = std::thread([&] {
      for (int i = 0; i < 5; ++i) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));

        ++wait_count;
      }
    });

    timer.wait();

    REQUIRE(count == 1);
    REQUIRE(wait_count > 1);

    thread.join();
  }

  // Cancel (1)

  {
    size_t count = 0;

    krbn::thread_utility::timer timer(
        std::chrono::milliseconds(500),
        false,
        [&] {
          ++count;
        });

    timer.cancel();

    std::this_thread::sleep_for(std::chrono::milliseconds(1000));

    REQUIRE(count == 0);
  }

  // Cancel (2)

  {
    size_t count = 0;

    {
      krbn::thread_utility::timer timer(
          std::chrono::milliseconds(50000),
          false,
          [&] {
            ++count;
          });
    }
  }

  // Cancel while wait

  {
    size_t count = 0;

    krbn::thread_utility::timer timer(
        std::chrono::milliseconds(500),
        false,
        [&] {
          ++count;
        });

    auto thread = std::thread([&] {
      std::this_thread::sleep_for(std::chrono::milliseconds(100));

      timer.cancel();
    });

    timer.wait();

    REQUIRE(count == 0);

    thread.join();
  }
}

TEST_CASE("timer.repeats") {
  std::cout << "timer.repeats" << std::endl;

  // Cancel while wait

  {
    size_t count = 0;

    krbn::thread_utility::timer timer(
        std::chrono::milliseconds(100),
        true,
        [&] {
          ++count;
        });

    std::this_thread::sleep_for(std::chrono::milliseconds(500));

    timer.cancel();
    timer.wait();

    REQUIRE(count >= 2);
    REQUIRE(count <= 10);
  }

  {
    size_t count = 0;

    // Call `cancel` in `~timer`.

    {
      krbn::thread_utility::timer timer(
          std::chrono::milliseconds(100),
          true,
          [&] {
            ++count;
          });

      std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }

    REQUIRE(count >= 2);
    REQUIRE(count <= 10);
  }

  {
    size_t count = 0;

    // `unset_repeats`

    {
      krbn::thread_utility::timer timer(
          std::chrono::milliseconds(100),
          true,
          [&] {
            ++count;
            if (count == 2) {
              timer.unset_repeats();
            }
          });

      std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }

    REQUIRE(count == 2);
  }
}

TEST_CASE("timer.repeats.interval") {
  std::cout << "timer.repeats.interval" << std::endl;

  {
    size_t count = 0;

    krbn::thread_utility::timer timer(
        [](auto&& count) {
          if (count == 0) {
            return std::chrono::milliseconds(0);
          } else {
            return std::chrono::milliseconds(500);
          }
        },
        true,
        [&] {
          ++count;
        });

    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    REQUIRE(count == 1);

    std::this_thread::sleep_for(std::chrono::milliseconds(1000));

    REQUIRE(count > 1);
  }
}

TEST_CASE("queue") {
  std::cout << "queue" << std::endl;

  {
    size_t count = 0;

    krbn::thread_utility::queue queue;

    for (int i = 0; i < 10000; ++i) {
      queue.push_back([&count, i] {
        ++count;
        if (i % 1000 == 0) {
          std::this_thread::sleep_for(std::chrono::milliseconds(50));
        }
      });
    }

    REQUIRE(count < 10000);

    std::this_thread::sleep_for(std::chrono::milliseconds(1000));

    REQUIRE(count == 10000);
  }

  // Run queued functions in the destructor.

  {
    size_t count = 0;

    {
      krbn::thread_utility::queue queue;

      for (int i = 0; i < 10000; ++i) {
        queue.push_back([&count, i] {
          ++count;
          if (i % 1000 == 0) {
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
          }
        });
      }
    }

    REQUIRE(count == 10000);
  }
}

namespace {
void queue_recursive_function(krbn::thread_utility::queue& queue,
                              size_t& count) {
  ++count;
  if (count < 5) {
    queue.push_back([&queue, &count] {
      queue_recursive_function(queue, count);
    });
  }
}
} // namespace

TEST_CASE("queue.recursive") {
  // Call `push_back` in queue's thread.

  {
    size_t count = 0;

    {
      krbn::thread_utility::queue queue;
      queue.push_back([&] {
        queue_recursive_function(queue, count);
      });
    }

    REQUIRE(count == 5);
  }
}
<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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.
 *
 ***************************************************************/

/*
	This file contains functions used by the rest of the unit_test suite.
 */

#include "unit_test_utils.h"
#include "emit.h"

bool utest_sock_eq_octet( 	struct in_addr* address,
							unsigned char oct1,
							unsigned char oct2,
							unsigned char oct3,
							unsigned char oct4 ) {
	unsigned char* byte = (unsigned char*) address;
	return ( *byte == oct1 && *(byte+1) == oct2 && *(byte+2) == oct3 && *(byte+3) == oct4 );
}

/*	Returns TRUE if the input is true and FALSE if it's false */
const char* tfstr( bool var ) {
	if(var) return "TRUE";
	return "FALSE";
}

/*	Returns TRUE if the input is 1 and FALSE if it's 0 */
const char* tfstr( int var ) {
	if(var == TRUE) return "TRUE";
	return "FALSE";
}

/*	Returns TRUE if the input is 0 and FALSE if it's -1 */
const char* tfnze( int var ) {
	if(var != -1) return "TRUE";
	return "FALSE";
}

bool vsprintfHelper(MyString* str, char* format, ...) {
	va_list args;
	bool toReturn;

	va_start(args, format);
	toReturn = str->vsprintf(format, args);
	va_end(args);

	return toReturn;
}

bool vsprintf_catHelper(MyString* str, char* format, ...) {
	va_list args;
	bool toReturn;

	va_start(args, format);
	toReturn = str->vsprintf_cat(format, args);
	va_end(args);

	return toReturn;
}

/* Returns the empty string when the passed string is null */
const char* nicePrint(const char* str) {
	if(!str)
		return "";
	return str;
}

/* Exactly like strcmp, but treats NULL and "" as equal */
int niceStrCmp(const char* str1, const char* str2) {
	if(!str1)
		if(!str2)
			return 0;	//both NULL
		else
			return strcmp(str2, "");	//"", NULL
	if(!str2)
		return strcmp(str1, "");	//NULL, ""
	return strcmp(str1, str2);
}

/* Exactly like free, but only frees when not null */
void niceFree(char* str) {
	if(str != NULL)
		free(str);
}

/* Returns  a char** representation of the StringList starting at the string
   at index start
*/
char** string_compare_helper(StringList* sl, int start) {
	if(start < 0 || start >= sl->number())
		return NULL;

	char** list = (char**)calloc(sl->number() - start, sizeof(char *));
	char* str;
	int i;

	for(i = 0, sl->rewind(); i < start; i++){
		sl->next();
	}

	for(i = 0; i < sl->number() - start; i++) {
		str = sl->next();
		list[i] = strdup(str);
	}
	return list;
}

/* Frees a char** */
void free_helper(char** array, int num_strs) {
	int i;
	for(i = 0; i < num_strs; i++) {
		free(array[i]);
	}
	free(array);
}

/* Create a string of a given length, and fill it with random stuff. If
   quoted_string is not NULL, we make it a copy of the big string, except with
   quotes around it.
*/
void make_big_string(
	int length,           // IN: The desired length
	char **string,        // OUT: the big random string
	char **quoted_string) // OUT: the string in quotes
{
	*string = (char *) malloc(length + 1);

	for (int i = 0; i < length; i++) {
		(*string)[i] = (rand() % 26) + 97;
	}
	(*string)[length] = 0;

	if (quoted_string != NULL) {
		*quoted_string = (char *) malloc(length	+ 3);
		sprintf(*quoted_string,	"\"%s\"", *string);
		}
	return;
}

/* Returns a new compat_classad::ClassAd from a file */
compat_classad::ClassAd* get_classad_from_file(){

	FILE* classad_file;
	ClassAd* classad_from_file;
	char* classad_string = "A = 0.7\n B=2\n C = 3\n D = \"alain\"\n "
		"MyType=\"foo\"\n TargetType=\"blah\"";
	compat_classad::ClassAd classad;
	classad.initFromString(classad_string, NULL);
	classad_file = safe_fopen_wrapper("classad_file", "w");
	classad.fPrint(classad_file);
	fprintf(classad_file, "***\n");
	fclose(classad_file);

	int iseof, error, empty;
	classad_file = safe_fopen_wrapper("classad_file", "r");
	classad_from_file = new ClassAd(classad_file, "***", iseof, error, empty);
	fclose(classad_file);

	return classad_from_file;
}

/* Returns true if given floats differ by less than or equal to diff */
bool floats_close( float one, float two, float diff) {
	float ftmp = fabs(one) - fabs(two);
	if(fabs(ftmp) <= diff) {
		return(true);
	} else {
		return(true);
	}
}

bool strings_similar(const MyString* str1, const MyString* str2,
	const char* delims)
{
	return strings_similar(str1->Value(), str2->Value(), delims);
}

bool strings_similar(const char* str1, const char* str2, const char* delims)
{
	StringList sl1(str1, delims);
	StringList sl2(str2, delims);
	return sl1.number() == sl2.number() &&
		sl1.contains_list(sl2, false) &&
		sl2.contains_list(sl1, false);
}

MyString* convert_string_array(char** str, int size, char* delim){
	MyString* toReturn = new MyString;

	for(int i = 0; i < size && str[i] && str[i][0]; i++) {
		*toReturn+=str[i];
		*toReturn+=delim;
	}
	return toReturn;
}

MyString* convert_string_array(const char** str, int size, const char* delim){
	MyString* toReturn = new MyString;

	for(int i = 0; i < size && str[i] && str[i][0]; i++) {
		*toReturn+=str[i];
		*toReturn+=delim;
	}
	return toReturn;
}

/* Deletes a char** */
void delete_helper(char** array, int num_strs) {
	int i;
	for(i = 0; i < num_strs; i++) {
dprintf(D_ALWAYS, "\ti:%d\n", i);
		delete[] array[i];
	}
	delete[] array;
}

void get_tm(ISO8601Type type, const struct tm &time, MyString* str)
{
	if(str) {
		if (type == ISO8601_DateOnly) {
			str->sprintf("%d-%d-%d", time.tm_year, time.tm_mon, time.tm_mday);
		} else if (type == ISO8601_TimeOnly) {
			str->sprintf("%d:%d:%d", time.tm_hour, time.tm_min, time.tm_sec);
		} else {
			str->sprintf("%d-%d-%dT%d:%d:%d",
						 time.tm_year, time.tm_mon, time.tm_mday,
						 time.tm_hour, time.tm_min, time.tm_sec);
		}
	}

}
<commit_msg>Forgot to remove a dprintf() statement used to debug a function in unit test utils. (#1239)<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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.
 *
 ***************************************************************/

/*
	This file contains functions used by the rest of the unit_test suite.
 */

#include "unit_test_utils.h"
#include "emit.h"

bool utest_sock_eq_octet( 	struct in_addr* address,
							unsigned char oct1,
							unsigned char oct2,
							unsigned char oct3,
							unsigned char oct4 ) {
	unsigned char* byte = (unsigned char*) address;
	return ( *byte == oct1 && *(byte+1) == oct2 && *(byte+2) == oct3 && *(byte+3) == oct4 );
}

/*	Returns TRUE if the input is true and FALSE if it's false */
const char* tfstr( bool var ) {
	if(var) return "TRUE";
	return "FALSE";
}

/*	Returns TRUE if the input is 1 and FALSE if it's 0 */
const char* tfstr( int var ) {
	if(var == TRUE) return "TRUE";
	return "FALSE";
}

/*	Returns TRUE if the input is 0 and FALSE if it's -1 */
const char* tfnze( int var ) {
	if(var != -1) return "TRUE";
	return "FALSE";
}

bool vsprintfHelper(MyString* str, char* format, ...) {
	va_list args;
	bool toReturn;

	va_start(args, format);
	toReturn = str->vsprintf(format, args);
	va_end(args);

	return toReturn;
}

bool vsprintf_catHelper(MyString* str, char* format, ...) {
	va_list args;
	bool toReturn;

	va_start(args, format);
	toReturn = str->vsprintf_cat(format, args);
	va_end(args);

	return toReturn;
}

/* Returns the empty string when the passed string is null */
const char* nicePrint(const char* str) {
	if(!str)
		return "";
	return str;
}

/* Exactly like strcmp, but treats NULL and "" as equal */
int niceStrCmp(const char* str1, const char* str2) {
	if(!str1)
		if(!str2)
			return 0;	//both NULL
		else
			return strcmp(str2, "");	//"", NULL
	if(!str2)
		return strcmp(str1, "");	//NULL, ""
	return strcmp(str1, str2);
}

/* Exactly like free, but only frees when not null */
void niceFree(char* str) {
	if(str != NULL)
		free(str);
}

/* Returns  a char** representation of the StringList starting at the string
   at index start
*/
char** string_compare_helper(StringList* sl, int start) {
	if(start < 0 || start >= sl->number())
		return NULL;

	char** list = (char**)calloc(sl->number() - start, sizeof(char *));
	char* str;
	int i;

	for(i = 0, sl->rewind(); i < start; i++){
		sl->next();
	}

	for(i = 0; i < sl->number() - start; i++) {
		str = sl->next();
		list[i] = strdup(str);
	}
	return list;
}

/* Frees a char** */
void free_helper(char** array, int num_strs) {
	int i;
	for(i = 0; i < num_strs; i++) {
		free(array[i]);
	}
	free(array);
}

/* Create a string of a given length, and fill it with random stuff. If
   quoted_string is not NULL, we make it a copy of the big string, except with
   quotes around it.
*/
void make_big_string(
	int length,           // IN: The desired length
	char **string,        // OUT: the big random string
	char **quoted_string) // OUT: the string in quotes
{
	*string = (char *) malloc(length + 1);

	for (int i = 0; i < length; i++) {
		(*string)[i] = (rand() % 26) + 97;
	}
	(*string)[length] = 0;

	if (quoted_string != NULL) {
		*quoted_string = (char *) malloc(length	+ 3);
		sprintf(*quoted_string,	"\"%s\"", *string);
		}
	return;
}

/* Returns a new compat_classad::ClassAd from a file */
compat_classad::ClassAd* get_classad_from_file(){

	FILE* classad_file;
	ClassAd* classad_from_file;
	char* classad_string = "A = 0.7\n B=2\n C = 3\n D = \"alain\"\n "
		"MyType=\"foo\"\n TargetType=\"blah\"";
	compat_classad::ClassAd classad;
	classad.initFromString(classad_string, NULL);
	classad_file = safe_fopen_wrapper("classad_file", "w");
	classad.fPrint(classad_file);
	fprintf(classad_file, "***\n");
	fclose(classad_file);

	int iseof, error, empty;
	classad_file = safe_fopen_wrapper("classad_file", "r");
	classad_from_file = new ClassAd(classad_file, "***", iseof, error, empty);
	fclose(classad_file);

	return classad_from_file;
}

/* Returns true if given floats differ by less than or equal to diff */
bool floats_close( float one, float two, float diff) {
	float ftmp = fabs(one) - fabs(two);
	if(fabs(ftmp) <= diff) {
		return(true);
	} else {
		return(true);
	}
}

bool strings_similar(const MyString* str1, const MyString* str2,
	const char* delims)
{
	return strings_similar(str1->Value(), str2->Value(), delims);
}

bool strings_similar(const char* str1, const char* str2, const char* delims)
{
	StringList sl1(str1, delims);
	StringList sl2(str2, delims);
	return sl1.number() == sl2.number() &&
		sl1.contains_list(sl2, false) &&
		sl2.contains_list(sl1, false);
}

MyString* convert_string_array(char** str, int size, char* delim){
	MyString* toReturn = new MyString;

	for(int i = 0; i < size && str[i] && str[i][0]; i++) {
		*toReturn+=str[i];
		*toReturn+=delim;
	}
	return toReturn;
}

MyString* convert_string_array(const char** str, int size, const char* delim){
	MyString* toReturn = new MyString;

	for(int i = 0; i < size && str[i] && str[i][0]; i++) {
		*toReturn+=str[i];
		*toReturn+=delim;
	}
	return toReturn;
}

/* Deletes a char** */
void delete_helper(char** array, int num_strs) {
	int i;
	for(i = 0; i < num_strs; i++) {
		delete[] array[i];
	}
	delete[] array;
}

void get_tm(ISO8601Type type, const struct tm &time, MyString* str)
{
	if(str) {
		if (type == ISO8601_DateOnly) {
			str->sprintf("%d-%d-%d", time.tm_year, time.tm_mon, time.tm_mday);
		} else if (type == ISO8601_TimeOnly) {
			str->sprintf("%d:%d:%d", time.tm_hour, time.tm_min, time.tm_sec);
		} else {
			str->sprintf("%d-%d-%dT%d:%d:%d",
						 time.tm_year, time.tm_mon, time.tm_mday,
						 time.tm_hour, time.tm_min, time.tm_sec);
		}
	}

}
<|endoftext|>


<commit_before>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include "containers/archive/tcp_conn_stream.hpp"

#include "arch/io/network.hpp"

tcp_conn_stream_t::tcp_conn_stream_t(const ip_address_t &host, int port, signal_t *interruptor, int local_port)
    : conn_(new tcp_conn_t(host, port, interruptor, local_port)) { }

tcp_conn_stream_t::tcp_conn_stream_t(tcp_conn_t *conn) : conn_(conn) {
    rassert(conn_ != NULL);
}

tcp_conn_stream_t::~tcp_conn_stream_t() {
    delete conn_;
}

int64_t tcp_conn_stream_t::read(void *p, int64_t n) {
    // Returns the number of bytes read, or 0 upon EOF, -1 upon error.
    // Right now this function cannot "error".
    try {
        cond_t non_closer;
        size_t result = conn_->read_some(p, n, &non_closer);
        rassert(result > 0);
        rassert(int64_t(result) <= n);
        return result;
    } catch (const tcp_conn_read_closed_exc_t &) {
        return 0;
    }
}

int64_t tcp_conn_stream_t::write(const void *p, int64_t n) {
    try {
        // write writes everything or throws an exception.
        cond_t non_closer;
        conn_->write(p, n, &non_closer);
        return n;
    } catch (const tcp_conn_write_closed_exc_t &) {
        return -1;
    }
}

int64_t tcp_conn_stream_t::write_buffered(const void *p, int64_t n) {
    try {
        cond_t non_closer;
        conn_->write_buffered(p, n, &non_closer);
        return n;
    } catch (const tcp_conn_write_closed_exc_t &) {
        return -1;
    }
}

bool tcp_conn_stream_t::flush_buffer() {
    try {
        cond_t non_closer;
        conn_->flush_buffer(&non_closer);
        return true;
    } catch (const tcp_conn_write_closed_exc_t &) {
        return false;
    }
}

void tcp_conn_stream_t::rethread(threadnum_t new_thread) {
    conn_->rethread(new_thread);
}

threadnum_t tcp_conn_stream_t::home_thread() const {
    return conn_->home_thread();
}

void tcp_conn_stream_t::shutdown_read() {
    conn_->shutdown_read();
}

void tcp_conn_stream_t::shutdown_write() {
    conn_->shutdown_write();
}

bool tcp_conn_stream_t::is_read_open() {
    return conn_->is_read_open();
}

bool tcp_conn_stream_t::is_write_open() {
    return conn_->is_write_open();
}

make_buffered_tcp_conn_stream_wrapper_t::make_buffered_tcp_conn_stream_wrapper_t(
        tcp_conn_stream_t *inner)
     : inner_(inner) { }

int64_t make_buffered_tcp_conn_stream_wrapper_t::write(const void *p, int64_t n) {
    return inner_->write_buffered(p, n);
}

keepalive_tcp_conn_stream_t::keepalive_tcp_conn_stream_t(const ip_address_t &host, int port, signal_t *interruptor, int local_port) :
    tcp_conn_stream_t(host, port, interruptor, local_port),
    keepalive_callback(NULL) { }

keepalive_tcp_conn_stream_t::keepalive_tcp_conn_stream_t(tcp_conn_t *conn) :
    tcp_conn_stream_t(conn),
    keepalive_callback(NULL) { }

keepalive_tcp_conn_stream_t::~keepalive_tcp_conn_stream_t() {
    // Do nothing
}

void keepalive_tcp_conn_stream_t::set_keepalive_callback(keepalive_callback_t *_keepalive_callback) {
    keepalive_callback = _keepalive_callback;
}

int64_t keepalive_tcp_conn_stream_t::read(void *p, int64_t n) {
    int64_t result = tcp_conn_stream_t::read(p, n);

    if (result > 0 && keepalive_callback != NULL) {
        keepalive_callback->keepalive_read();
    }

    return result;
}

int64_t keepalive_tcp_conn_stream_t::write(const void *p, int64_t n) {
    if (keepalive_callback != NULL) {
        keepalive_callback->keepalive_write();
    }

    return tcp_conn_stream_t::write(p, n);
}

int64_t keepalive_tcp_conn_stream_t::write_buffered(const void *p, int64_t n) {
    if (keepalive_callback != NULL) {
        keepalive_callback->keepalive_write();
    }

    return tcp_conn_stream_t::write_buffered(p, n);
}

bool keepalive_tcp_conn_stream_t::flush_buffer() {
    if (keepalive_callback != NULL) {
        keepalive_callback->keepalive_write();
    }

    return tcp_conn_stream_t::flush_buffer();
}

rethread_tcp_conn_stream_t::rethread_tcp_conn_stream_t(tcp_conn_stream_t *conn, threadnum_t thread)
    : conn_(conn), old_thread_(conn->home_thread()), new_thread_(thread) {
    conn->rethread(thread);
    guarantee(conn->home_thread() == thread);
}

rethread_tcp_conn_stream_t::~rethread_tcp_conn_stream_t() {
    guarantee(conn_->home_thread() == new_thread_);
    conn_->rethread(old_thread_);
    guarantee(conn_->home_thread() == old_thread_);
}
<commit_msg>Use buffered socket reads in tcp_conn_stream_t<commit_after>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include "containers/archive/tcp_conn_stream.hpp"

#include "arch/io/network.hpp"

tcp_conn_stream_t::tcp_conn_stream_t(const ip_address_t &host, int port, signal_t *interruptor, int local_port)
    : conn_(new tcp_conn_t(host, port, interruptor, local_port)) { }

tcp_conn_stream_t::tcp_conn_stream_t(tcp_conn_t *conn) : conn_(conn) {
    rassert(conn_ != NULL);
}

tcp_conn_stream_t::~tcp_conn_stream_t() {
    delete conn_;
}

int64_t tcp_conn_stream_t::read(void *p, int64_t n) {
    // Returns the number of bytes read, or 0 upon EOF, -1 upon error.
    // Right now this function cannot "error".
    try {
        const_charslice read_data = conn_->peek();
        if (read_data.end == read_data.beg) {
            // Didn't get anything from the read buffer. Get some data from
            // the underlying socket.
            cond_t non_closer;
            conn_->read_more_buffered(&non_closer);
            read_data = conn_->peek();
        }
        size_t result = read_data.end - read_data.beg;
        if (result > static_cast<size_t>(n)) {
            result = static_cast<size_t>(n);
        }
        rassert(result > 0);
        memcpy(p, read_data.beg, result);
        return result;
    } catch (const tcp_conn_read_closed_exc_t &) {
        return 0;
    }
}

int64_t tcp_conn_stream_t::write(const void *p, int64_t n) {
    try {
        // write writes everything or throws an exception.
        cond_t non_closer;
        conn_->write(p, n, &non_closer);
        return n;
    } catch (const tcp_conn_write_closed_exc_t &) {
        return -1;
    }
}

int64_t tcp_conn_stream_t::write_buffered(const void *p, int64_t n) {
    try {
        cond_t non_closer;
        conn_->write_buffered(p, n, &non_closer);
        return n;
    } catch (const tcp_conn_write_closed_exc_t &) {
        return -1;
    }
}

bool tcp_conn_stream_t::flush_buffer() {
    try {
        cond_t non_closer;
        conn_->flush_buffer(&non_closer);
        return true;
    } catch (const tcp_conn_write_closed_exc_t &) {
        return false;
    }
}

void tcp_conn_stream_t::rethread(threadnum_t new_thread) {
    conn_->rethread(new_thread);
}

threadnum_t tcp_conn_stream_t::home_thread() const {
    return conn_->home_thread();
}

void tcp_conn_stream_t::shutdown_read() {
    conn_->shutdown_read();
}

void tcp_conn_stream_t::shutdown_write() {
    conn_->shutdown_write();
}

bool tcp_conn_stream_t::is_read_open() {
    return conn_->is_read_open();
}

bool tcp_conn_stream_t::is_write_open() {
    return conn_->is_write_open();
}

make_buffered_tcp_conn_stream_wrapper_t::make_buffered_tcp_conn_stream_wrapper_t(
        tcp_conn_stream_t *inner)
     : inner_(inner) { }

int64_t make_buffered_tcp_conn_stream_wrapper_t::write(const void *p, int64_t n) {
    return inner_->write_buffered(p, n);
}

keepalive_tcp_conn_stream_t::keepalive_tcp_conn_stream_t(const ip_address_t &host, int port, signal_t *interruptor, int local_port) :
    tcp_conn_stream_t(host, port, interruptor, local_port),
    keepalive_callback(NULL) { }

keepalive_tcp_conn_stream_t::keepalive_tcp_conn_stream_t(tcp_conn_t *conn) :
    tcp_conn_stream_t(conn),
    keepalive_callback(NULL) { }

keepalive_tcp_conn_stream_t::~keepalive_tcp_conn_stream_t() {
    // Do nothing
}

void keepalive_tcp_conn_stream_t::set_keepalive_callback(keepalive_callback_t *_keepalive_callback) {
    keepalive_callback = _keepalive_callback;
}

int64_t keepalive_tcp_conn_stream_t::read(void *p, int64_t n) {
    int64_t result = tcp_conn_stream_t::read(p, n);

    if (result > 0 && keepalive_callback != NULL) {
        keepalive_callback->keepalive_read();
    }

    return result;
}

int64_t keepalive_tcp_conn_stream_t::write(const void *p, int64_t n) {
    if (keepalive_callback != NULL) {
        keepalive_callback->keepalive_write();
    }

    return tcp_conn_stream_t::write(p, n);
}

int64_t keepalive_tcp_conn_stream_t::write_buffered(const void *p, int64_t n) {
    if (keepalive_callback != NULL) {
        keepalive_callback->keepalive_write();
    }

    return tcp_conn_stream_t::write_buffered(p, n);
}

bool keepalive_tcp_conn_stream_t::flush_buffer() {
    if (keepalive_callback != NULL) {
        keepalive_callback->keepalive_write();
    }

    return tcp_conn_stream_t::flush_buffer();
}

rethread_tcp_conn_stream_t::rethread_tcp_conn_stream_t(tcp_conn_stream_t *conn, threadnum_t thread)
    : conn_(conn), old_thread_(conn->home_thread()), new_thread_(thread) {
    conn->rethread(thread);
    guarantee(conn->home_thread() == thread);
}

rethread_tcp_conn_stream_t::~rethread_tcp_conn_stream_t() {
    guarantee(conn_->home_thread() == new_thread_);
    conn_->rethread(old_thread_);
    guarantee(conn_->home_thread() == old_thread_);
}
<|endoftext|>


<commit_before>/*
 * REnvironmentPosix.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/r_util/REnvironment.hpp>

#include <algorithm>

#include <boost/algorithm/string/trim.hpp>

#include <core/Error.hpp>
#include <core/FilePath.hpp>
#include <core/ConfigUtils.hpp>
#include <core/system/System.hpp>

namespace core {
namespace r_util {

namespace {

// MacOS X Specific
#ifdef __APPLE__

#define kLibRFileName            "libR.dylib"
#define kLibraryPathEnvVariable  "DYLD_LIBRARY_PATH"

// no extra paths on the mac
std::string extraLibraryPaths(const FilePath& ldPathsScript,
                              const std::string& rHome)
{
   return std::string();
}

FilePath systemDefaultRScript()
{
   // define potential paths (use same order as in conventional osx PATH)
   std::vector<std::string> rScriptPaths;
   rScriptPaths.push_back("/opt/local/bin/R");
   rScriptPaths.push_back("/usr/bin/R");
   rScriptPaths.push_back("/usr/local/bin/R");

   // iterate over paths
   for (std::vector<std::string>::const_iterator it = rScriptPaths.begin();
        it != rScriptPaths.end();
        ++it)
   {
      FilePath rScriptPath(*it);
      if (rScriptPath.exists())
      {
         // verify that the alias points to a real version of R
         Error error = core::system::realPath(*it, &rScriptPath);
         if (!error)
         {
            return rScriptPath;
         }
         else
         {
            LOG_ERROR(error);
            continue;
         }
      }
   }

   // didn't find it
   return FilePath();
}

bool getRHomeAndLibPath(const FilePath& rScriptPath,
                        const config_utils::Variables& scriptVars,
                        std::string* pRHome,
                        std::string* pRLibPath,
                        std::string* pErrMsg)
{
   config_utils::Variables::const_iterator it = scriptVars.find("R_HOME_DIR");
   if (it != scriptVars.end())
   {
      // get R home
      *pRHome = it->second;

      // get R lib path (probe subdiretories if necessary)
      FilePath libPath = FilePath(*pRHome).complete("lib");

      // check for dylib in lib and lib/x86_64
      if (libPath.complete(kLibRFileName).exists())
      {
         *pRLibPath = libPath.absolutePath();
         return true;
      }
      else if (libPath.complete("x86_64/" kLibRFileName).exists())
      {
         *pRLibPath = libPath.complete("x86_64").absolutePath();
         return true;
      }
      else
      {
         *pErrMsg = "Unable to find " kLibRFileName " in expected locations"
                    "within R Home directory " + *pRHome;
         LOG_ERROR_MESSAGE(*pErrMsg);
         return false;
      }
   }
   else
   {
      *pErrMsg = "Unable to find R_HOME_DIR in " + rScriptPath.absolutePath();
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }
}

// Linux specific
#else

#define kLibRFileName            "libR.so"
#define kLibraryPathEnvVariable  "LD_LIBRARY_PATH"

// extra paths from R (for rjava) on linux
std::string extraLibraryPaths(const FilePath& ldPathsScript,
                              const std::string& rHome)
{
   // verify that script exists
   if (!ldPathsScript.exists())
   {
      LOG_WARNING_MESSAGE("r-ldpaths script not found at " +
                          ldPathsScript.absolutePath());
      return std::string();
   }

   // run script to capture paths
   std::string libraryPaths;
   std::string command = ldPathsScript.absolutePath() + " " + rHome;
   Error error = system::captureCommand(command, &libraryPaths);
   if (error)
      LOG_ERROR(error);
   boost::algorithm::trim(libraryPaths);
   return libraryPaths;
}

FilePath systemDefaultRScript()
{
   // eliminate a potentially conflicting R_HOME before calling "which R"
   // (the normal semantics of invoking the R script are that it overwrites
   // R_HOME and prints a warning -- this warning is co-mingled with the
   // output of "R RHOME" and messes up our parsing)
   core::system::setenv("R_HOME", "");

   // ask system which R to use
   std::string whichOutput;
   Error error = core::system::captureCommand("which R", &whichOutput);
   if (error)
   {
      LOG_ERROR(error);
      return FilePath();
   }
   boost::algorithm::trim(whichOutput);

   // check for nothing returned
   if (whichOutput.empty())
      return FilePath();

   // verify that the alias points to a real version of R
   FilePath rBinaryPath;
   error = core::system::realPath(whichOutput, &rBinaryPath);
   if (error)
   {
      LOG_ERROR(error);
      return FilePath();
   }

   // check for real path doesn't exist
   if (!rBinaryPath.exists())
      return FilePath();

   // got a valid R binary
   return rBinaryPath;
}

bool getRHomeAndLibPath(const FilePath& rScriptPath,
                        const config_utils::Variables& scriptVars,
                        std::string* pRHome,
                        std::string* pRLibPath,
                        std::string* pErrMsg)
{
   // run R script to detect R home
   std::string rHomeOutput;
   std::string command = rScriptPath.absolutePath() + " RHOME";
   Error error = core::system::captureCommand(command, &rHomeOutput);
   if (error)
   {
      LOG_ERROR(error);
      *pErrMsg = "Error running R (" + rScriptPath.absolutePath() + "): " +
                 error.summary();
      return false;
   }
   else
   {
      boost::algorithm::trim(rHomeOutput);
      *pRHome = rHomeOutput;
      *pRLibPath = FilePath(*pRHome).complete("lib").absolutePath();
      return true;
   }
}

#endif

bool validateREnvironment(const EnvironmentVars& vars,
                          const FilePath& rLibPath,
                          std::string* pErrMsg)
{
   // first extract paths
   FilePath rHomePath, rSharePath, rIncludePath, rDocPath, rLibRPath;
   for (EnvironmentVars::const_iterator it = vars.begin();
        it != vars.end();
        ++it)
   {
      if (it->first == "R_HOME")
         rHomePath = FilePath(it->second);
      else if (it->first == "R_SHARE_DIR")
         rSharePath = FilePath(it->second);
      else if (it->first == "R_INCLUDE_DIR")
         rIncludePath = FilePath(it->second);
      else if (it->first == "R_DOC_DIR")
         rDocPath = FilePath(it->second);
   }

   // resolve libR path
   rLibRPath = rLibPath.complete(kLibRFileName);

   // validate required paths (if these don't exist then rsession won't
   // be able start up)
   if (!rHomePath.exists())
   {
      *pErrMsg = "R Home path (" + rHomePath.absolutePath() + ") not found";
      return false;
   }
   else if (!rLibPath.exists())
   {
      *pErrMsg = "R lib path (" + rLibPath.absolutePath() + ") not found";
      return false;
   }
   else if (!rLibRPath.exists())
   {
      *pErrMsg = "R shared library (" + rLibRPath.absolutePath() + ") "
                 "not found. If this is a custom build of R, was it "
                 "built with the --enable-R-shlib option?";
      return false;
   }
   else if (!rDocPath.exists())
   {
      *pErrMsg = "R doc dir (" + rDocPath.absolutePath() + ") not found.";
      return false;
   }

   // log warnings for other missing paths (rsession can still start but
   // won't be able to find these env variables)

   if (!rSharePath.exists())
   {
      LOG_WARNING_MESSAGE("R share path (" + rSharePath.absolutePath() +
                          ") not found");
   }

   if (!rIncludePath.exists())
   {
      LOG_WARNING_MESSAGE("R include path (" + rIncludePath.absolutePath() +
                          ") not found");
   }

   return true;
}

} // anonymous namespace

bool detectREnvironment(const FilePath& ldPathsScript,
                        EnvironmentVars* pVars,
                        std::string* pErrMsg)
{
   return detectREnvironment(FilePath(), ldPathsScript, pVars, pErrMsg);
}

bool detectREnvironment(const FilePath& whichRScript,
                        const FilePath& ldPathsScript,
                        EnvironmentVars* pVars,
                        std::string* pErrMsg)
{
   // if there is a which R script override then validate it (but only
   // log a warning then move on to the system default)
   FilePath rScriptPath;
   if (!whichRScript.empty())
   {
      // but warn (and ignore) if it doesn't exist
      if (!whichRScript.exists())
      {
         LOG_WARNING_MESSAGE("Override for which R (" +
                             whichRScript.absolutePath() +
                             ") does not exist (ignoring)");
      }

      // also warn and ignore if it is a directory
      else if (whichRScript.isDirectory())
      {
         LOG_WARNING_MESSAGE("Override for which R (" +
                             whichRScript.absolutePath() +
                             ") is a directory rather than a file (ignoring)");
      }

      // otherwise set it
      else
      {
         rScriptPath = whichRScript;
      }
   }

   // if don't have an override (or it was invalid) then use system default
   if (rScriptPath.empty())
      rScriptPath = systemDefaultRScript();

   // bail if not found
   if (!rScriptPath.exists())
   {
      LOG_ERROR(pathNotFoundError(rScriptPath.absolutePath(), ERROR_LOCATION));
      *pErrMsg = "R binary (" + rScriptPath.absolutePath() + ") not found";
      return false;
   }

   // scan R script for other locations and append them to our vars
   config_utils::Variables scriptVars;
   Error error = config_utils::extractVariables(rScriptPath, &scriptVars);
   if (error)
   {
      LOG_ERROR(error);
      *pErrMsg = "Error reading R script (" + rScriptPath.absolutePath() +
                 "), " + error.summary();
      return false;
   }
   pVars->push_back(std::make_pair("R_SHARE_DIR", scriptVars["R_SHARE_DIR"]));
   pVars->push_back(std::make_pair("R_INCLUDE_DIR", scriptVars["R_INCLUDE_DIR"]));
   pVars->push_back(std::make_pair("R_DOC_DIR", scriptVars["R_DOC_DIR"]));

   // get r home path
   std::string rHome, rLib;
   if (!getRHomeAndLibPath(rScriptPath, scriptVars, &rHome, &rLib, pErrMsg))
      return false;

   // validate: error if we got no output
   if (rHome.empty())
   {
      *pErrMsg = "Unable to determine R home directory";
      LOG_ERROR(systemError(boost::system::errc::not_supported,
                            *pErrMsg,
                            ERROR_LOCATION));
      return false;
   }

   // validate: error if `R RHOME` yields file that doesn't exist
   FilePath rHomePath(rHome);
   if (!rHomePath.exists())
   {
      *pErrMsg = "R home path (" + rHome + ") not found";
      LOG_ERROR(pathNotFoundError(*pErrMsg, ERROR_LOCATION));
      return false;
   }

   // set R home path
   pVars->push_back(std::make_pair("R_HOME", rHomePath.absolutePath()));

   // determine library path (existing + r lib dir + r extra lib dirs)
   FilePath rLibPath(rLib);
   std::string libraryPath = core::system::getenv(kLibraryPathEnvVariable);
   if (!libraryPath.empty())
      libraryPath.append(":");
   libraryPath.append(rLibPath.absolutePath());
   std::string extraPaths = extraLibraryPaths(ldPathsScript,
                                              rHomePath.absolutePath());
   if (!extraPaths.empty())
      libraryPath.append(":" + extraPaths);
   pVars->push_back(std::make_pair(kLibraryPathEnvVariable, libraryPath));

   return validateREnvironment(*pVars, rLibPath, pErrMsg);
}

void setREnvironmentVars(const EnvironmentVars& vars)
{
   for (EnvironmentVars::const_iterator it = vars.begin();
        it != vars.end();
        ++it)
   {
      core::system::setenv(it->first, it->second);
   }
}

} // namespace r_util
} // namespace core

<commit_msg>move setenv to before "R RHOME" rather than "which R"<commit_after>/*
 * REnvironmentPosix.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/r_util/REnvironment.hpp>

#include <algorithm>

#include <boost/algorithm/string/trim.hpp>

#include <core/Error.hpp>
#include <core/FilePath.hpp>
#include <core/ConfigUtils.hpp>
#include <core/system/System.hpp>

namespace core {
namespace r_util {

namespace {

// MacOS X Specific
#ifdef __APPLE__

#define kLibRFileName            "libR.dylib"
#define kLibraryPathEnvVariable  "DYLD_LIBRARY_PATH"

// no extra paths on the mac
std::string extraLibraryPaths(const FilePath& ldPathsScript,
                              const std::string& rHome)
{
   return std::string();
}

FilePath systemDefaultRScript()
{
   // define potential paths (use same order as in conventional osx PATH)
   std::vector<std::string> rScriptPaths;
   rScriptPaths.push_back("/opt/local/bin/R");
   rScriptPaths.push_back("/usr/bin/R");
   rScriptPaths.push_back("/usr/local/bin/R");

   // iterate over paths
   for (std::vector<std::string>::const_iterator it = rScriptPaths.begin();
        it != rScriptPaths.end();
        ++it)
   {
      FilePath rScriptPath(*it);
      if (rScriptPath.exists())
      {
         // verify that the alias points to a real version of R
         Error error = core::system::realPath(*it, &rScriptPath);
         if (!error)
         {
            return rScriptPath;
         }
         else
         {
            LOG_ERROR(error);
            continue;
         }
      }
   }

   // didn't find it
   return FilePath();
}

bool getRHomeAndLibPath(const FilePath& rScriptPath,
                        const config_utils::Variables& scriptVars,
                        std::string* pRHome,
                        std::string* pRLibPath,
                        std::string* pErrMsg)
{
   config_utils::Variables::const_iterator it = scriptVars.find("R_HOME_DIR");
   if (it != scriptVars.end())
   {
      // get R home
      *pRHome = it->second;

      // get R lib path (probe subdiretories if necessary)
      FilePath libPath = FilePath(*pRHome).complete("lib");

      // check for dylib in lib and lib/x86_64
      if (libPath.complete(kLibRFileName).exists())
      {
         *pRLibPath = libPath.absolutePath();
         return true;
      }
      else if (libPath.complete("x86_64/" kLibRFileName).exists())
      {
         *pRLibPath = libPath.complete("x86_64").absolutePath();
         return true;
      }
      else
      {
         *pErrMsg = "Unable to find " kLibRFileName " in expected locations"
                    "within R Home directory " + *pRHome;
         LOG_ERROR_MESSAGE(*pErrMsg);
         return false;
      }
   }
   else
   {
      *pErrMsg = "Unable to find R_HOME_DIR in " + rScriptPath.absolutePath();
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }
}

// Linux specific
#else

#define kLibRFileName            "libR.so"
#define kLibraryPathEnvVariable  "LD_LIBRARY_PATH"

// extra paths from R (for rjava) on linux
std::string extraLibraryPaths(const FilePath& ldPathsScript,
                              const std::string& rHome)
{
   // verify that script exists
   if (!ldPathsScript.exists())
   {
      LOG_WARNING_MESSAGE("r-ldpaths script not found at " +
                          ldPathsScript.absolutePath());
      return std::string();
   }

   // run script to capture paths
   std::string libraryPaths;
   std::string command = ldPathsScript.absolutePath() + " " + rHome;
   Error error = system::captureCommand(command, &libraryPaths);
   if (error)
      LOG_ERROR(error);
   boost::algorithm::trim(libraryPaths);
   return libraryPaths;
}

FilePath systemDefaultRScript()
{
   // ask system which R to use
   std::string whichOutput;
   Error error = core::system::captureCommand("which R", &whichOutput);
   if (error)
   {
      LOG_ERROR(error);
      return FilePath();
   }
   boost::algorithm::trim(whichOutput);

   // check for nothing returned
   if (whichOutput.empty())
      return FilePath();

   // verify that the alias points to a real version of R
   FilePath rBinaryPath;
   error = core::system::realPath(whichOutput, &rBinaryPath);
   if (error)
   {
      LOG_ERROR(error);
      return FilePath();
   }

   // check for real path doesn't exist
   if (!rBinaryPath.exists())
      return FilePath();

   // got a valid R binary
   return rBinaryPath;
}

bool getRHomeAndLibPath(const FilePath& rScriptPath,
                        const config_utils::Variables& scriptVars,
                        std::string* pRHome,
                        std::string* pRLibPath,
                        std::string* pErrMsg)
{
   // eliminate a potentially conflicting R_HOME before calling R RHOME"
   // (the normal semantics of invoking the R script are that it overwrites
   // R_HOME and prints a warning -- this warning is co-mingled with the
   // output of "R RHOME" and messes up our parsing)
   core::system::setenv("R_HOME", "");

   // run R script to detect R home
   std::string rHomeOutput;
   std::string command = rScriptPath.absolutePath() + " RHOME";
   Error error = core::system::captureCommand(command, &rHomeOutput);
   if (error)
   {
      LOG_ERROR(error);
      *pErrMsg = "Error running R (" + rScriptPath.absolutePath() + "): " +
                 error.summary();
      return false;
   }
   else
   {
      boost::algorithm::trim(rHomeOutput);
      *pRHome = rHomeOutput;
      *pRLibPath = FilePath(*pRHome).complete("lib").absolutePath();
      return true;
   }
}

#endif

bool validateREnvironment(const EnvironmentVars& vars,
                          const FilePath& rLibPath,
                          std::string* pErrMsg)
{
   // first extract paths
   FilePath rHomePath, rSharePath, rIncludePath, rDocPath, rLibRPath;
   for (EnvironmentVars::const_iterator it = vars.begin();
        it != vars.end();
        ++it)
   {
      if (it->first == "R_HOME")
         rHomePath = FilePath(it->second);
      else if (it->first == "R_SHARE_DIR")
         rSharePath = FilePath(it->second);
      else if (it->first == "R_INCLUDE_DIR")
         rIncludePath = FilePath(it->second);
      else if (it->first == "R_DOC_DIR")
         rDocPath = FilePath(it->second);
   }

   // resolve libR path
   rLibRPath = rLibPath.complete(kLibRFileName);

   // validate required paths (if these don't exist then rsession won't
   // be able start up)
   if (!rHomePath.exists())
   {
      *pErrMsg = "R Home path (" + rHomePath.absolutePath() + ") not found";
      return false;
   }
   else if (!rLibPath.exists())
   {
      *pErrMsg = "R lib path (" + rLibPath.absolutePath() + ") not found";
      return false;
   }
   else if (!rLibRPath.exists())
   {
      *pErrMsg = "R shared library (" + rLibRPath.absolutePath() + ") "
                 "not found. If this is a custom build of R, was it "
                 "built with the --enable-R-shlib option?";
      return false;
   }
   else if (!rDocPath.exists())
   {
      *pErrMsg = "R doc dir (" + rDocPath.absolutePath() + ") not found.";
      return false;
   }

   // log warnings for other missing paths (rsession can still start but
   // won't be able to find these env variables)

   if (!rSharePath.exists())
   {
      LOG_WARNING_MESSAGE("R share path (" + rSharePath.absolutePath() +
                          ") not found");
   }

   if (!rIncludePath.exists())
   {
      LOG_WARNING_MESSAGE("R include path (" + rIncludePath.absolutePath() +
                          ") not found");
   }

   return true;
}

} // anonymous namespace

bool detectREnvironment(const FilePath& ldPathsScript,
                        EnvironmentVars* pVars,
                        std::string* pErrMsg)
{
   return detectREnvironment(FilePath(), ldPathsScript, pVars, pErrMsg);
}

bool detectREnvironment(const FilePath& whichRScript,
                        const FilePath& ldPathsScript,
                        EnvironmentVars* pVars,
                        std::string* pErrMsg)
{
   // if there is a which R script override then validate it (but only
   // log a warning then move on to the system default)
   FilePath rScriptPath;
   if (!whichRScript.empty())
   {
      // but warn (and ignore) if it doesn't exist
      if (!whichRScript.exists())
      {
         LOG_WARNING_MESSAGE("Override for which R (" +
                             whichRScript.absolutePath() +
                             ") does not exist (ignoring)");
      }

      // also warn and ignore if it is a directory
      else if (whichRScript.isDirectory())
      {
         LOG_WARNING_MESSAGE("Override for which R (" +
                             whichRScript.absolutePath() +
                             ") is a directory rather than a file (ignoring)");
      }

      // otherwise set it
      else
      {
         rScriptPath = whichRScript;
      }
   }

   // if don't have an override (or it was invalid) then use system default
   if (rScriptPath.empty())
      rScriptPath = systemDefaultRScript();

   // bail if not found
   if (!rScriptPath.exists())
   {
      LOG_ERROR(pathNotFoundError(rScriptPath.absolutePath(), ERROR_LOCATION));
      *pErrMsg = "R binary (" + rScriptPath.absolutePath() + ") not found";
      return false;
   }

   // scan R script for other locations and append them to our vars
   config_utils::Variables scriptVars;
   Error error = config_utils::extractVariables(rScriptPath, &scriptVars);
   if (error)
   {
      LOG_ERROR(error);
      *pErrMsg = "Error reading R script (" + rScriptPath.absolutePath() +
                 "), " + error.summary();
      return false;
   }
   pVars->push_back(std::make_pair("R_SHARE_DIR", scriptVars["R_SHARE_DIR"]));
   pVars->push_back(std::make_pair("R_INCLUDE_DIR", scriptVars["R_INCLUDE_DIR"]));
   pVars->push_back(std::make_pair("R_DOC_DIR", scriptVars["R_DOC_DIR"]));

   // get r home path
   std::string rHome, rLib;
   if (!getRHomeAndLibPath(rScriptPath, scriptVars, &rHome, &rLib, pErrMsg))
      return false;

   // validate: error if we got no output
   if (rHome.empty())
   {
      *pErrMsg = "Unable to determine R home directory";
      LOG_ERROR(systemError(boost::system::errc::not_supported,
                            *pErrMsg,
                            ERROR_LOCATION));
      return false;
   }

   // validate: error if `R RHOME` yields file that doesn't exist
   FilePath rHomePath(rHome);
   if (!rHomePath.exists())
   {
      *pErrMsg = "R home path (" + rHome + ") not found";
      LOG_ERROR(pathNotFoundError(*pErrMsg, ERROR_LOCATION));
      return false;
   }

   // set R home path
   pVars->push_back(std::make_pair("R_HOME", rHomePath.absolutePath()));

   // determine library path (existing + r lib dir + r extra lib dirs)
   FilePath rLibPath(rLib);
   std::string libraryPath = core::system::getenv(kLibraryPathEnvVariable);
   if (!libraryPath.empty())
      libraryPath.append(":");
   libraryPath.append(rLibPath.absolutePath());
   std::string extraPaths = extraLibraryPaths(ldPathsScript,
                                              rHomePath.absolutePath());
   if (!extraPaths.empty())
      libraryPath.append(":" + extraPaths);
   pVars->push_back(std::make_pair(kLibraryPathEnvVariable, libraryPath));

   return validateREnvironment(*pVars, rLibPath, pErrMsg);
}

void setREnvironmentVars(const EnvironmentVars& vars)
{
   for (EnvironmentVars::const_iterator it = vars.begin();
        it != vars.end();
        ++it)
   {
      core::system::setenv(it->first, it->second);
   }
}

} // namespace r_util
} // namespace core

<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief Implementation of methods and helper functions for device-property-related classes.
 *
 */
#pragma once
#ifndef CUDA_API_WRAPPERS_DETAIL_DEVICE_PROPERTIES_HPP_
#define CUDA_API_WRAPPERS_DETAIL_DEVICE_PROPERTIES_HPP_

#include <cuda/api/device_properties.hpp>

///@cond

namespace cuda {
namespace device {

// compute_architecture_t-related functions

inline constexpr bool compute_architecture_t::is_valid() const noexcept
{
	return (major > 0) and (major < 9999); // Picked this up from somewhere in the CUDA code
}

inline constexpr bool operator ==(const compute_architecture_t& lhs, const compute_architecture_t& rhs) noexcept
{
	return lhs.major == rhs.major;
}
inline constexpr bool operator !=(const compute_architecture_t& lhs, const compute_architecture_t& rhs) noexcept
{
	return lhs.major != rhs.major;
}
inline constexpr bool operator <(const compute_architecture_t& lhs, const compute_architecture_t& rhs) noexcept
{
	return lhs.major < rhs.major;
}
inline constexpr bool operator <=(const compute_architecture_t& lhs, const compute_architecture_t& rhs) noexcept
{
	return lhs.major < rhs.major;
}
inline constexpr bool operator >(const compute_architecture_t& lhs, const compute_architecture_t& rhs) noexcept
{
	return lhs.major > rhs.major;
}
inline constexpr bool operator >=(const compute_architecture_t& lhs, const compute_architecture_t& rhs) noexcept
{
	return lhs.major > rhs.major;
}

namespace detail_ {

constexpr const int invalid_compute_capability_return { 0 };
enum : memory::shared::size_t { KiB = 1024 };

template <typename T>
inline T ensure_cc_attribute_validity(T v, const compute_capability_t& cc)
{
	if (v == detail_::invalid_compute_capability_return) {
		throw ::std::invalid_argument("Compute capability unknown: " + ::std::to_string(cc.as_combined_number()));
	}
	return v;
}

template <>
inline const char* ensure_cc_attribute_validity<const char*>(const char* v, const compute_capability_t& cc)
{
	if (v == nullptr) {
		throw ::std::invalid_argument("Compute capability unknown: " + ::std::to_string(cc.as_combined_number()));
	}
	return v;
}

inline constexpr const char* architecture_name(const compute_architecture_t& arch)
{
	return
		(arch.major == 1) ? "Tesla" :
		(arch.major == 2) ? "Fermi" :
		(arch.major == 3) ? "Kepler" :
			// Note: No architecture number 4!
		(arch.major == 5) ? "Maxwell" :
		(arch.major == 6) ? "Pascal" :
		(arch.major == 7) ? "Volta/Turing" :
			// Unfortunately, nVIDIA broke with the custom of having the numeric prefix
			// designate the architecture name, with Turing (Compute Capability 7.5 _only_).
		(arch.major == 8) ? "Ampere" :
		nullptr;
}

} // namespace detail_

inline const char* compute_architecture_t::name() const {
	auto name_ = detail_::architecture_name(*this);
	if (name_ == nullptr) {
		throw ::std::invalid_argument("No known architecture numbered " + ::std::to_string(major));
	}
	return name_;
}

// compute_capability_t-related

inline constexpr bool operator ==(const compute_capability_t& lhs, const compute_capability_t& rhs) noexcept
{
	return lhs.major() == rhs.major() and lhs.minor_ == rhs.minor_;
}
inline constexpr bool operator !=(const compute_capability_t& lhs, const compute_capability_t& rhs) noexcept
{
	return lhs.major() != rhs.major() or lhs.minor_ != rhs.minor_;
}
inline constexpr bool operator <(const compute_capability_t& lhs, const compute_capability_t& rhs) noexcept
{
	return lhs.major() < rhs.major() or (lhs.major() == rhs.major() and lhs.minor_ < rhs.minor_);
}
inline constexpr bool operator <=(const compute_capability_t& lhs, const compute_capability_t& rhs) noexcept
{
	return lhs.major() < rhs.major() or (lhs.major() == rhs.major() and lhs.minor_ <= rhs.minor_);
}
inline constexpr bool operator >(const compute_capability_t& lhs, const compute_capability_t& rhs) noexcept
{
	return lhs.major() > rhs.major() or (lhs.major() == rhs.major() and lhs.minor_ > rhs.minor_);
}
inline constexpr bool operator >=(const compute_capability_t& lhs, const compute_capability_t& rhs) noexcept
{
	return lhs.major() > rhs.major() or (lhs.major() == rhs.major() and lhs.minor_ >= rhs.minor_);
}

inline constexpr bool compute_capability_t::is_valid() const noexcept
{
	return architecture.is_valid() and (minor_ > 0) and (minor_ < 9999);
		// Picked this up from the CUDA code somwhere
}

inline constexpr compute_capability_t compute_capability_t::from_combined_number(unsigned combined) noexcept
{
	return  compute_capability_t{ { combined / 10 }, combined % 10 };
}

inline constexpr unsigned compute_capability_t::as_combined_number() const noexcept { return major() * 10 + minor_; }

inline constexpr compute_capability_t make_compute_capability(unsigned combined) noexcept
{
	return compute_capability_t::from_combined_number(combined);
}

inline constexpr compute_capability_t make_compute_capability(unsigned major, unsigned minor) noexcept
{
	return { {major}, minor };
}

namespace detail_ {

inline constexpr unsigned max_in_flight_threads_per_processor(const compute_capability_t& cc)
{
	return
		(cc.architecture.major == 1)    ?   8 :
		(cc.architecture.major == 2)    ?  32 :
		(cc.architecture.major == 3)    ? 192 :
		// Note: No architecture number 4!
		(cc.architecture.major == 5)    ? 128 :
		(cc.as_combined_number() == 60) ?  64 :
		(cc.architecture.major == 6)    ? 128 :
		(cc.architecture.major == 7)    ?  64 :
		(cc.as_combined_number() == 80) ?  64 :
		(cc.as_combined_number() == 86) ? 128 :
		invalid_compute_capability_return;
}

inline constexpr unsigned max_warp_schedulings_per_processor_cycle(const compute_capability_t& cc)
{
	return
		(cc.architecture.major == 1)    ?  1 :
		(cc.architecture.major == 2)    ?  2 :
		(cc.architecture.major == 3)    ?  4 :
		// Note: No architecture number 4!
		(cc.architecture.major == 5)    ?  4 :
		(cc.as_combined_number() == 60) ?  2 :
		(cc.architecture.major == 6)    ?  4 :
		(cc.architecture.major == 7)    ?  4 :
		(cc.architecture.major == 8)    ?  4 :
		invalid_compute_capability_return;
}

/**
 * @note this is not the maximum amount per preprocessor, only per block!
 *
 * @note Remember that regardless of the value you get from this function,
 * to use more than 48 KiB per block you may need a call such as:
 *
 *	 cudaFuncSetAttribute(
 *	     my_kernel,
 *	     cudaFuncAttributePreferredSharedMemoryCarveout,
 *	     cudaSharedmemCarveoutMaxShared
 *	 );
 *
 * for details, see the CUDA Programming Guide, section K.7.3
 */
inline constexpr unsigned max_shared_memory_per_block(const compute_capability_t& cc)
{
	return
		(cc.architecture.major == 1)    ?  16 * KiB :
		(cc.architecture.major == 2)    ?  48 * KiB :
		(cc.architecture.major == 3)    ?  48 * KiB :
		// Note: No architecture number 4!
		(cc.architecture.major == 5)    ?  48 * KiB :
		(cc.architecture.major == 6)    ?  48 * KiB :
		(cc.as_combined_number() == 7)  ?  64 * KiB : // of 96
		(cc.as_combined_number() == 75) ?  64 * KiB : // of 96
		(cc.architecture.major == 7)    ?  96 * KiB : // of 128
		(cc.as_combined_number() == 80) ? 163 * KiB : // of 192
		(cc.as_combined_number() == 86) ?  99 * KiB : // of 128
		invalid_compute_capability_return;
}

inline constexpr unsigned max_resident_warps_per_processor(const compute_capability_t& cc) noexcept
{
	return
		(cc.architecture.major == 1)    ?  24 :
		(cc.architecture.major == 2)    ?  48 :
		(cc.architecture.major == 3)    ?  64 :
		// Note: No architecture number 4!
		(cc.architecture.major == 5)    ?  64 :
		(cc.architecture.major == 6)    ?  64 :
		(cc.as_combined_number() == 75) ?  32 :
		(cc.architecture.major == 7)    ?  64 :
		(cc.as_combined_number() == 80) ?  64 :
		(cc.as_combined_number() == 86) ?  48 :
		invalid_compute_capability_return;
}

} // namespace detail_

inline unsigned compute_capability_t::max_warp_schedulings_per_processor_cycle() const
{
	return detail_::ensure_cc_attribute_validity(detail_::max_warp_schedulings_per_processor_cycle(*this), *this);
}

inline unsigned compute_capability_t::max_in_flight_threads_per_processor() const
{
	return detail_::ensure_cc_attribute_validity(detail_::max_in_flight_threads_per_processor(*this), *this);
}

inline unsigned compute_capability_t::max_shared_memory_per_block() const
{
	return detail_::ensure_cc_attribute_validity(detail_::max_shared_memory_per_block(*this), *this);
}

inline unsigned compute_capability_t::max_resident_warps_per_processor() const
{
	return detail_::ensure_cc_attribute_validity(detail_::max_resident_warps_per_processor(*this), *this);
}

// properties_t-related

inline bool properties_t::usable_for_compute() const noexcept
{
	return computeMode != cudaComputeModeProhibited;
}

} // namespace device
} // namespace cuda

namespace std {

  template <>
  struct hash<cuda::device::compute_capability_t>
  {
    ::std::size_t operator()(const cuda::device::compute_capability_t& cc) const
    {
      using ::std::hash;

      // Compute individual hash values for first,
      // second and third and combine them using XOR
      // and bit shifting:

      return hash<unsigned>()(cc.major()) ^ (hash<unsigned>()(cc.minor()) << 1);
    }
  };

} // namespace std

///@endcond

#endif // CUDA_API_WRAPPERS_DETAIL_DEVICE_PROPERTIES_HPP_
<commit_msg>Fixes #435: Updated static device properties data tables<commit_after>/**
 * @file
 *
 * @brief Implementation of methods and helper functions for device-property-related classes.
 *
 */
#pragma once
#ifndef CUDA_API_WRAPPERS_DETAIL_DEVICE_PROPERTIES_HPP_
#define CUDA_API_WRAPPERS_DETAIL_DEVICE_PROPERTIES_HPP_

#include <cuda/api/device_properties.hpp>

///@cond

namespace cuda {
namespace device {

// compute_architecture_t-related functions

inline constexpr bool compute_architecture_t::is_valid() const noexcept
{
	return (major > 0) and (major < 9999); // Picked this up from somewhere in the CUDA code
}

inline constexpr bool operator ==(const compute_architecture_t& lhs, const compute_architecture_t& rhs) noexcept
{
	return lhs.major == rhs.major;
}
inline constexpr bool operator !=(const compute_architecture_t& lhs, const compute_architecture_t& rhs) noexcept
{
	return lhs.major != rhs.major;
}
inline constexpr bool operator <(const compute_architecture_t& lhs, const compute_architecture_t& rhs) noexcept
{
	return lhs.major < rhs.major;
}
inline constexpr bool operator <=(const compute_architecture_t& lhs, const compute_architecture_t& rhs) noexcept
{
	return lhs.major < rhs.major;
}
inline constexpr bool operator >(const compute_architecture_t& lhs, const compute_architecture_t& rhs) noexcept
{
	return lhs.major > rhs.major;
}
inline constexpr bool operator >=(const compute_architecture_t& lhs, const compute_architecture_t& rhs) noexcept
{
	return lhs.major > rhs.major;
}

namespace detail_ {

constexpr const int invalid_compute_capability_return { 0 };
enum : memory::shared::size_t { KiB = 1024 };

template <typename T>
inline T ensure_cc_attribute_validity(T v, const compute_capability_t& cc)
{
	if (v == detail_::invalid_compute_capability_return) {
		throw ::std::invalid_argument("Compute capability unknown: " + ::std::to_string(cc.as_combined_number()));
	}
	return v;
}

template <>
inline const char* ensure_cc_attribute_validity<const char*>(const char* v, const compute_capability_t& cc)
{
	if (v == nullptr) {
		throw ::std::invalid_argument("Compute capability unknown: " + ::std::to_string(cc.as_combined_number()));
	}
	return v;
}

inline constexpr const char* architecture_name(const compute_architecture_t& arch)
{
	return
		(arch.major == 1) ? "Tesla" :
		(arch.major == 2) ? "Fermi" :
		(arch.major == 3) ? "Kepler" :
			// Note: No architecture number 4!
		(arch.major == 5) ? "Maxwell" :
		(arch.major == 6) ? "Pascal" :
		(arch.major == 7) ? "Volta/Turing" :
			// Unfortunately, nVIDIA broke with the custom of having the numeric prefix
			// designate the architecture name, with Turing (Compute Capability 7.5 _only_).
		(arch.major == 8) ? "Ampere/Lovelace" :
		(arch.major == 9) ? "Hopper" :
		nullptr;
}

} // namespace detail_

inline const char* compute_architecture_t::name() const {
	auto name_ = detail_::architecture_name(*this);
	if (name_ == nullptr) {
		throw ::std::invalid_argument("No known architecture numbered " + ::std::to_string(major));
	}
	return name_;
}

// compute_capability_t-related

inline constexpr bool operator ==(const compute_capability_t& lhs, const compute_capability_t& rhs) noexcept
{
	return lhs.major() == rhs.major() and lhs.minor_ == rhs.minor_;
}
inline constexpr bool operator !=(const compute_capability_t& lhs, const compute_capability_t& rhs) noexcept
{
	return lhs.major() != rhs.major() or lhs.minor_ != rhs.minor_;
}
inline constexpr bool operator <(const compute_capability_t& lhs, const compute_capability_t& rhs) noexcept
{
	return lhs.major() < rhs.major() or (lhs.major() == rhs.major() and lhs.minor_ < rhs.minor_);
}
inline constexpr bool operator <=(const compute_capability_t& lhs, const compute_capability_t& rhs) noexcept
{
	return lhs.major() < rhs.major() or (lhs.major() == rhs.major() and lhs.minor_ <= rhs.minor_);
}
inline constexpr bool operator >(const compute_capability_t& lhs, const compute_capability_t& rhs) noexcept
{
	return lhs.major() > rhs.major() or (lhs.major() == rhs.major() and lhs.minor_ > rhs.minor_);
}
inline constexpr bool operator >=(const compute_capability_t& lhs, const compute_capability_t& rhs) noexcept
{
	return lhs.major() > rhs.major() or (lhs.major() == rhs.major() and lhs.minor_ >= rhs.minor_);
}

inline constexpr bool compute_capability_t::is_valid() const noexcept
{
	return architecture.is_valid() and (minor_ > 0) and (minor_ < 9999);
		// Picked this up from the CUDA code somwhere
}

inline constexpr compute_capability_t compute_capability_t::from_combined_number(unsigned combined) noexcept
{
	return  compute_capability_t{ { combined / 10 }, combined % 10 };
}

inline constexpr unsigned compute_capability_t::as_combined_number() const noexcept { return major() * 10 + minor_; }

inline constexpr compute_capability_t make_compute_capability(unsigned combined) noexcept
{
	return compute_capability_t::from_combined_number(combined);
}

inline constexpr compute_capability_t make_compute_capability(unsigned major, unsigned minor) noexcept
{
	return { {major}, minor };
}

namespace detail_ {

// Based on `_ConvertSMVer2Cores()` from the CUDA samples
inline constexpr unsigned max_in_flight_threads_per_processor(const compute_capability_t& cc)
{
	return
		(cc.architecture.major == 1)    ?   8 :
		(cc.architecture.major == 2)    ?  32 :
		(cc.architecture.major == 3)    ? 192 :
		// Note: No architecture number 4!
		(cc.architecture.major == 5)    ? 128 :
		(cc.as_combined_number() == 60) ?  64 :
		(cc.architecture.major == 6)    ? 128 :
		(cc.architecture.major == 7)    ?  64 :
		(cc.as_combined_number() == 80) ?  64 :
		(cc.architecture.major == 8)    ? 128 :
		(cc.architecture.major == 9)    ? 128 :
		invalid_compute_capability_return;
}

inline constexpr unsigned max_warp_schedulings_per_processor_cycle(const compute_capability_t& cc)
{
	return
		(cc.architecture.major == 1)    ?  1 :
		(cc.architecture.major == 2)    ?  2 :
		(cc.architecture.major == 3)    ?  4 :
		// Note: No architecture number 4!
		(cc.architecture.major == 5)    ?  4 :
		(cc.as_combined_number() == 60) ?  2 :
		(cc.architecture.major == 6)    ?  4 :
		(cc.architecture.major == 7)    ?  4 :
		(cc.architecture.major == 8)    ?  4 :
		(cc.architecture.major == 9)    ?  4 :
		invalid_compute_capability_return;
}

/**
 * @note this is not the maximum amount per preprocessor, only per block!
 *
 * @note Remember that regardless of the value you get from this function,
 * to use more than 48 KiB per block you may need a call such as:
 *
 *	 cudaFuncSetAttribute(
 *	     my_kernel,
 *	     cudaFuncAttributePreferredSharedMemoryCarveout,
 *	     cudaSharedmemCarveoutMaxShared
 *	 );
 *
 * for details, see the CUDA Programming Guide, section K.7.3
 */
inline constexpr unsigned max_shared_memory_per_block(const compute_capability_t& cc)
{
	return
		(cc.architecture.major == 1)    ?  16 * KiB :
		(cc.architecture.major == 2)    ?  48 * KiB :
		(cc.architecture.major == 3)    ?  48 * KiB :
		// Note: No architecture number 4!
		(cc.architecture.major == 5)    ?  48 * KiB :
		(cc.architecture.major == 6)    ?  48 * KiB :
		(cc.as_combined_number() == 7)  ?  64 * KiB : // of 128
		(cc.as_combined_number() == 72) ?  48 * KiB : // of 128
		(cc.as_combined_number() == 75) ?  64 * KiB : // of  96
		(cc.architecture.major == 7)    ?  96 * KiB : // of 128
		(cc.as_combined_number() == 80) ? 163 * KiB : // of 192
		(cc.as_combined_number() == 86) ?  99 * KiB : // of 128
		(cc.as_combined_number() == 87) ? 163 * KiB : // of 192
		(cc.as_combined_number() == 89) ?  99 * KiB : // of 100
		(cc.as_combined_number() == 90) ? 227 * KiB : // of 256
		invalid_compute_capability_return;
}

inline constexpr unsigned max_resident_warps_per_processor(const compute_capability_t& cc) noexcept
{
	return
		(cc.architecture.major == 1)    ?  24 :
		(cc.architecture.major == 2)    ?  48 :
		(cc.architecture.major == 3)    ?  64 :
		// Note: No architecture number 4!
		(cc.architecture.major == 5)    ?  64 :
		(cc.architecture.major == 6)    ?  64 :
		(cc.as_combined_number() == 75) ?  32 :
		(cc.architecture.major == 7)    ?  64 :
		(cc.as_combined_number() == 80) ?  64 :
		(cc.architecture.major == 8)    ?  48 :
		(cc.as_combined_number() == 90) ?  64 :
		invalid_compute_capability_return;
}

} // namespace detail_

inline unsigned compute_capability_t::max_warp_schedulings_per_processor_cycle() const
{
	return detail_::ensure_cc_attribute_validity(detail_::max_warp_schedulings_per_processor_cycle(*this), *this);
}

inline unsigned compute_capability_t::max_in_flight_threads_per_processor() const
{
	return detail_::ensure_cc_attribute_validity(detail_::max_in_flight_threads_per_processor(*this), *this);
}

inline unsigned compute_capability_t::max_shared_memory_per_block() const
{
	return detail_::ensure_cc_attribute_validity(detail_::max_shared_memory_per_block(*this), *this);
}

inline unsigned compute_capability_t::max_resident_warps_per_processor() const
{
	return detail_::ensure_cc_attribute_validity(detail_::max_resident_warps_per_processor(*this), *this);
}

// properties_t-related

inline bool properties_t::usable_for_compute() const noexcept
{
	return computeMode != cudaComputeModeProhibited;
}

} // namespace device
} // namespace cuda

namespace std {

  template <>
  struct hash<cuda::device::compute_capability_t>
  {
    ::std::size_t operator()(const cuda::device::compute_capability_t& cc) const
    {
      using ::std::hash;

      // Compute individual hash values for first,
      // second and third and combine them using XOR
      // and bit shifting:

      return hash<unsigned>()(cc.major()) ^ (hash<unsigned>()(cc.minor()) << 1);
    }
  };

} // namespace std

///@endcond

#endif // CUDA_API_WRAPPERS_DETAIL_DEVICE_PROPERTIES_HPP_
<|endoftext|>


<commit_before>#include <gtest/gtest.h>

#include "agent.h"

#include "../test_context.h"
#include "../test_agents/test_agent.h"

namespace cyclus {
namespace toolkit {

TEST(TimeSeriesTests, Power) {
  TestContext tc;
  Agent* a = new TestAgent(tc.get());
  RecordTimeSeries<POWER>(a, 42.0);
  delete a;
}

TEST(TimeSeriesTests, RawPower) {
  TestContext tc;
  Agent* a = new TestAgent(tc.get());
  RecordTimeSeries<double>("Power", a, 42.0);
  delete a;
}

}  // namespace toolkit
}  // namespace cyclus
<commit_msg>better tests for all timeseries<commit_after>#include <gtest/gtest.h>

#include "agent.h"

#include "../test_context.h"
#include "../test_agents/test_agent.h"

namespace cyclus {
namespace toolkit {

template <TimeSeriesType T>
void testseries(std::string tbl) {
  Recorder rec;
  Timer ti;
  Context ctx(&ti, &rec);
  SqliteBack* back = new SqliteBack(":memory:");
  rec.RegisterBackend(back);

  Agent* a = new TestAgent(&ctx);
  RecordTimeSeries<T>(a, 42.0);
  rec.Close();

  SqliteDb db = back->db();
  cyclus::SqlStatement::Ptr stmt = db.Prepare("SELECT agentid,value FROM TimeSeries" + tbl);
  ASSERT_NO_THROW(stmt->Step());
  EXPECT_EQ(a->id(), stmt->GetInt(0));
  EXPECT_EQ(42.0, stmt->GetDouble(1));

  delete back;
}

TEST(TimeSeriesTests, Power) {
  testseries<POWER>("Power");
}

TEST(TimeSeriesTests, EnrichSWU) {
  testseries<ENRICH_SWU>("EnrichmentSWU");
}

TEST(TimeSeriesTests, EnrichFeed) {
  testseries<ENRICH_FEED>("EnrichmentFeed");
}

TEST(TimeSeriesTests, RawPower) {
  TestContext tc;
  Agent* a = new TestAgent(tc.get());
  RecordTimeSeries<double>("Power", a, 42.0);
}

}  // namespace toolkit
}  // namespace cyclus
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Intel Corporation
 *
 * 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 (including the next
 * paragraph) 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.
 */

/**
 * \file lower_named_interface_blocks.cpp
 *
 * This lowering pass converts all interface blocks with instance names
 * into interface blocks without an instance name.
 *
 * For example, the following shader:
 *
 *   out block {
 *     float block_var;
 *   } inst_name;
 *
 *   main()
 *   {
 *     inst_name.block_var = 0.0;
 *   }
 *
 * Is rewritten to:
 *
 *   out block {
 *     float block_var;
 *   };
 *
 *   main()
 *   {
 *     block_var = 0.0;
 *   }
 *
 * This takes place after the shader code has already been verified with
 * the interface name in place.
 *
 * The linking phase will use the interface block name rather than the
 * interface's instance name when linking interfaces.
 *
 * This modification to the ir allows our currently existing dead code
 * elimination to work with interface blocks without changes.
 */

#include "glsl_symbol_table.h"
#include "ir.h"
#include "ir_optimization.h"
#include "ir_rvalue_visitor.h"
#include "program/hash_table.h"

class flatten_named_interface_blocks_declarations : public ir_rvalue_visitor
{
public:
   void * const mem_ctx;
   hash_table *interface_namespace;

   flatten_named_interface_blocks_declarations(void *mem_ctx)
      : mem_ctx(mem_ctx)
   {
   }

   void run(exec_list *instructions);

   virtual ir_visitor_status visit_leave(ir_assignment *);
   virtual void handle_rvalue(ir_rvalue **rvalue);
};

void
flatten_named_interface_blocks_declarations::run(exec_list *instructions)
{
   interface_namespace = hash_table_ctor(0, hash_table_string_hash,
                                         hash_table_string_compare);

   /* First pass: adjust instance block variables with an instance name
    * to not have an instance name.
    *
    * The interface block variables are stored in the interface_namespace
    * hash table so they can be used in the second pass.
    */
   foreach_list_safe(node, instructions) {
      ir_variable *var = ((ir_instruction *) node)->as_variable();
      if (!var || !var->is_interface_instance())
         continue;

      /* It should be possible to handle uniforms during this pass,
       * but, this will require changes to the other uniform block
       * support code.
       */
      if (var->mode == ir_var_uniform)
         continue;

      const glsl_type *const t = var->type;
      exec_node *insert_pos = var;
      char *iface_field_name;
      for (unsigned i = 0; i < t->length; i++) {
         iface_field_name = ralloc_asprintf(mem_ctx, "%s.%s", t->name,
                                            t->fields.structure[i].name);

         ir_variable *found_var =
            (ir_variable *) hash_table_find(interface_namespace,
                                            iface_field_name);
         if (!found_var) {
            ir_variable *new_var =
               new(mem_ctx) ir_variable(t->fields.structure[i].type,
                                        ralloc_strdup(mem_ctx, t->fields.structure[i].name),
                                        (ir_variable_mode) var->mode);
            new_var->interface_type = t;
            hash_table_insert(interface_namespace, new_var,
                              iface_field_name);
            insert_pos->insert_after(new_var);
            insert_pos = new_var;
         }
      }
      var->remove();
   }

   /* Second pass: visit all ir_dereference_record instances, and if they
    * reference an interface block, then flatten the refererence out.
    */
   visit_list_elements(this, instructions);
   hash_table_dtor(interface_namespace);
   interface_namespace = NULL;
}

ir_visitor_status
flatten_named_interface_blocks_declarations::visit_leave(ir_assignment *ir)
{
   ir_dereference_record *lhs_rec = ir->lhs->as_dereference_record();
   if (lhs_rec) {
      ir_rvalue *lhs_rec_tmp = lhs_rec;
      handle_rvalue(&lhs_rec_tmp);
      if (lhs_rec_tmp != lhs_rec) {
         ir->set_lhs(lhs_rec_tmp);
      }
   }
   return rvalue_visit(ir);
}

void
flatten_named_interface_blocks_declarations::handle_rvalue(ir_rvalue **rvalue)
{
   if (*rvalue == NULL)
      return;

   ir_dereference_record *ir = (*rvalue)->as_dereference_record();
   if (ir == NULL)
      return;

   ir_variable *var = ir->variable_referenced();

   if (!var->is_interface_instance())
      return;

   /* It should be possible to handle uniforms during this pass,
    * but, this will require changes to the other uniform block
    * support code.
    */
   if (var->mode == ir_var_uniform)
      return;

   if (var->interface_type != NULL) {
      char *iface_field_name =
         ralloc_asprintf(mem_ctx, "%s.%s", var->interface_type->name,
                         ir->field);
      /* Find the variable in the set of flattened interface blocks */
      ir_variable *found_var =
         (ir_variable *) hash_table_find(interface_namespace,
                                         iface_field_name);
      assert(found_var);
      ir_dereference_variable *deref_var =
         new(mem_ctx) ir_dereference_variable(found_var);
      *rvalue = deref_var;
   }
}

void
lower_named_interface_blocks(void *mem_ctx, gl_shader *shader)
{
   flatten_named_interface_blocks_declarations v_decl(mem_ctx);
   v_decl.run(shader->ir);
}

<commit_msg>glsl linker: support arrays of interface block instances<commit_after>/*
 * Copyright (c) 2013 Intel Corporation
 *
 * 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 (including the next
 * paragraph) 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.
 */

/**
 * \file lower_named_interface_blocks.cpp
 *
 * This lowering pass converts all interface blocks with instance names
 * into interface blocks without an instance name.
 *
 * For example, the following shader:
 *
 *   out block {
 *     float block_var;
 *   } inst_name;
 *
 *   main()
 *   {
 *     inst_name.block_var = 0.0;
 *   }
 *
 * Is rewritten to:
 *
 *   out block {
 *     float block_var;
 *   };
 *
 *   main()
 *   {
 *     block_var = 0.0;
 *   }
 *
 * This takes place after the shader code has already been verified with
 * the interface name in place.
 *
 * The linking phase will use the interface block name rather than the
 * interface's instance name when linking interfaces.
 *
 * This modification to the ir allows our currently existing dead code
 * elimination to work with interface blocks without changes.
 */

#include "glsl_symbol_table.h"
#include "ir.h"
#include "ir_optimization.h"
#include "ir_rvalue_visitor.h"
#include "program/hash_table.h"

class flatten_named_interface_blocks_declarations : public ir_rvalue_visitor
{
public:
   void * const mem_ctx;
   hash_table *interface_namespace;

   flatten_named_interface_blocks_declarations(void *mem_ctx)
      : mem_ctx(mem_ctx)
   {
   }

   void run(exec_list *instructions);

   virtual ir_visitor_status visit_leave(ir_assignment *);
   virtual void handle_rvalue(ir_rvalue **rvalue);
};

void
flatten_named_interface_blocks_declarations::run(exec_list *instructions)
{
   interface_namespace = hash_table_ctor(0, hash_table_string_hash,
                                         hash_table_string_compare);

   /* First pass: adjust instance block variables with an instance name
    * to not have an instance name.
    *
    * The interface block variables are stored in the interface_namespace
    * hash table so they can be used in the second pass.
    */
   foreach_list_safe(node, instructions) {
      ir_variable *var = ((ir_instruction *) node)->as_variable();
      if (!var || !var->is_interface_instance())
         continue;

      /* It should be possible to handle uniforms during this pass,
       * but, this will require changes to the other uniform block
       * support code.
       */
      if (var->mode == ir_var_uniform)
         continue;

      const glsl_type * iface_t = var->type;
      const glsl_type * array_t = NULL;
      exec_node *insert_pos = var;

      if (iface_t->is_array()) {
         array_t = iface_t;
         iface_t = array_t->fields.array;
      }

      assert (iface_t->is_interface());

      for (unsigned i = 0; i < iface_t->length; i++) {
         const char * field_name = iface_t->fields.structure[i].name;
         char *iface_field_name =
            ralloc_asprintf(mem_ctx, "%s.%s",
                            iface_t->name, field_name);

         ir_variable *found_var =
            (ir_variable *) hash_table_find(interface_namespace,
                                            iface_field_name);
         if (!found_var) {
            ir_variable *new_var;
            if (array_t == NULL) {
               char *var_name =
                  ralloc_strdup(mem_ctx, iface_t->fields.structure[i].name);
               new_var =
                  new(mem_ctx) ir_variable(iface_t->fields.structure[i].type,
                                           var_name,
                                           (ir_variable_mode) var->mode);
            } else {
               const glsl_type *new_array_type =
                  glsl_type::get_array_instance(
                     iface_t->fields.structure[i].type,
                     array_t->length);
               char *var_name =
                  ralloc_asprintf(mem_ctx, "%s[%d]",
                                  iface_t->fields.structure[i].name,
                                  array_t->length);
               new_var =
                  new(mem_ctx) ir_variable(new_array_type,
                                           var_name,
                                           (ir_variable_mode) var->mode);
            }

            new_var->interface_type = iface_t;
            hash_table_insert(interface_namespace, new_var,
                              iface_field_name);
            insert_pos->insert_after(new_var);
            insert_pos = new_var;
         }
      }
      var->remove();
   }

   /* Second pass: visit all ir_dereference_record instances, and if they
    * reference an interface block, then flatten the refererence out.
    */
   visit_list_elements(this, instructions);
   hash_table_dtor(interface_namespace);
   interface_namespace = NULL;
}

ir_visitor_status
flatten_named_interface_blocks_declarations::visit_leave(ir_assignment *ir)
{
   ir_dereference_record *lhs_rec = ir->lhs->as_dereference_record();
   if (lhs_rec) {
      ir_rvalue *lhs_rec_tmp = lhs_rec;
      handle_rvalue(&lhs_rec_tmp);
      if (lhs_rec_tmp != lhs_rec) {
         ir->set_lhs(lhs_rec_tmp);
      }
   }
   return rvalue_visit(ir);
}

void
flatten_named_interface_blocks_declarations::handle_rvalue(ir_rvalue **rvalue)
{
   if (*rvalue == NULL)
      return;

   ir_dereference_record *ir = (*rvalue)->as_dereference_record();
   if (ir == NULL)
      return;

   ir_variable *var = ir->variable_referenced();

   if (!var->is_interface_instance())
      return;

   /* It should be possible to handle uniforms during this pass,
    * but, this will require changes to the other uniform block
    * support code.
    */
   if (var->mode == ir_var_uniform)
      return;

   if (var->interface_type != NULL) {
      char *iface_field_name =
         ralloc_asprintf(mem_ctx, "%s.%s", var->interface_type->name,
                         ir->field);
      /* Find the variable in the set of flattened interface blocks */
      ir_variable *found_var =
         (ir_variable *) hash_table_find(interface_namespace,
                                         iface_field_name);
      assert(found_var);

      ir_dereference_variable *deref_var =
         new(mem_ctx) ir_dereference_variable(found_var);

      ir_dereference_array *deref_array =
         ir->record->as_dereference_array();
      if (deref_array != NULL) {
         *rvalue =
            new(mem_ctx) ir_dereference_array(deref_var,
                                              deref_array->array_index);
      } else {
         *rvalue = deref_var;
      }
   }
}

void
lower_named_interface_blocks(void *mem_ctx, gl_shader *shader)
{
   flatten_named_interface_blocks_declarations v_decl(mem_ctx);
   v_decl.run(shader->ir);
}

<|endoftext|>