Mercurial > hg > openjdk > jdk8u > hotspot
changeset 8436:b1b140f0c504
Merge
author | asaha |
---|---|
date | Thu, 16 Feb 2017 13:21:41 -0800 |
parents | e49557628945 (current diff) c468dc338392 (diff) |
children | 268b63233d3e |
files | .hgtags |
diffstat | 19 files changed, 282 insertions(+), 49 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Mon Jan 23 17:09:40 2017 -0800 +++ b/.hgtags Thu Feb 16 13:21:41 2017 -0800 @@ -931,6 +931,8 @@ b28d012a24cab8f4ceeee0c9d3252969757423ed jdk8u112-b15 e134dc1879b72124e478be01680b0646a2fbf585 jdk8u112-b16 87440ed4e1de7753a436f957d35555d8b4e26f1d jdk8u112-b31 +ba25f5833a128b8062e597f794efda26b30f095d jdk8u112-b32 +919ffdca10c2721ee0f6f233e704709174556510 jdk8u112-b33 3b0e5f01891f5ebbf67797b1aae786196f1bb4f6 jdk8u121-b00 251a2493b1857f2ff4f11eab2dfd8b2fe8ed441b jdk8u121-b01 70c4a50f576a01ec975d0a02b3642ee33db39ed8 jdk8u121-b02 @@ -945,10 +947,14 @@ 11f91811e4d7e5ddfaf938dcf386ec8fe5bf7b7c jdk8u121-b11 b132b08b28bf23a26329928cf6b4ffda5857f4d3 jdk8u121-b12 90f94521c3515e5f27af0ab9b31d036e88bb322a jdk8u121-b13 +351bf1d4ff9a41137f91e2ec97ec59ed29a38d8b jdk8u121-b31 +41daac438a2ac5a80755dc3de88b76e4ac66750a jdk8u121-b32 c0a1ba0df20fda10ddb8599e888eb56ad98b3874 jdk8u131-b00 0b85ccd6240991e1a501602ff5addec6b88ae0af jdk8u131-b01 ef90c721a4e59b01ca36f25619010a1afe9ed4d5 jdk8u131-b02 0ca47d0811b01ecf8651b6045a1e33a4a9bed0ee jdk8u131-b03 dab1d597165207e14b6886b1823c1e990bc776a3 jdk8u131-b04 +c965fc1aa840a0903709ad69aa0e2100330ccd84 jdk8u131-b05 +6e4cfbc7534f83902692132efb61683528c04a59 jdk8u131-b06 692bc6b674dcab72453de08ee9da0856a7e41c0f jdk8u141-b00 2d5100bddeb80cf767485b787fc3051311e3d7b9 jdk8u151-b00
--- a/src/cpu/sparc/vm/macroAssembler_sparc.cpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/cpu/sparc/vm/macroAssembler_sparc.cpp Thu Feb 16 13:21:41 2017 -0800 @@ -4261,6 +4261,7 @@ assert(UseBlockZeroing && VM_Version::has_block_zeroing(), "only works with BIS zeroing"); Register end = count; int cache_line_size = VM_Version::prefetch_data_size(); + assert(cache_line_size > 0, "cache line size should be known for this code"); // Minimum count when BIS zeroing can be used since // it needs membar which is expensive. int block_zero_size = MAX2(cache_line_size*3, (int)BlockZeroingLowLimit);
--- a/src/cpu/sparc/vm/vm_version_sparc.cpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/cpu/sparc/vm/vm_version_sparc.cpp Thu Feb 16 13:21:41 2017 -0800 @@ -74,7 +74,7 @@ AllocatePrefetchDistance = AllocatePrefetchStepSize; } - if (AllocatePrefetchStyle == 3 && !has_blk_init()) { + if (AllocatePrefetchStyle == 3 && (!has_blk_init() || cache_line_size <= 0)) { warning("BIS instructions are not available on this CPU"); FLAG_SET_DEFAULT(AllocatePrefetchStyle, 1); } @@ -138,7 +138,7 @@ FLAG_SET_DEFAULT(InteriorEntryAlignment, 4); } if (is_niagara_plus()) { - if (has_blk_init() && UseTLAB && + if (has_blk_init() && (cache_line_size > 0) && UseTLAB && FLAG_IS_DEFAULT(AllocatePrefetchInstr)) { // Use BIS instruction for TLAB allocation prefetch. FLAG_SET_ERGO(intx, AllocatePrefetchInstr, 1);
--- a/src/os/linux/vm/globals_linux.hpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/os/linux/vm/globals_linux.hpp Thu Feb 16 13:21:41 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,10 @@ "Load DLLs with executable-stack attribute in the VM Thread") \ \ product(bool, UseSHM, false, \ - "Use SYSV shared memory for large pages") + "Use SYSV shared memory for large pages") \ + \ + diagnostic(bool, PrintActiveCpus, false, \ + "Print the number of CPUs detected in os::active_processor_count") // // Defines Linux-specific default values. The flags are available on all
--- a/src/os/linux/vm/os_linux.cpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/os/linux/vm/os_linux.cpp Thu Feb 16 13:21:41 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,6 +104,14 @@ PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC +#ifndef _GNU_SOURCE + #define _GNU_SOURCE + #include <sched.h> + #undef _GNU_SOURCE +#else + #include <sched.h> +#endif + // if RUSAGE_THREAD for getrusage() has not been defined, do it here. The code calling // getrusage() is prepared to handle the associated failure. #ifndef RUSAGE_THREAD @@ -1067,29 +1075,30 @@ // Locate initial thread stack. This special handling of initial thread stack // is needed because pthread_getattr_np() on most (all?) Linux distros returns -// bogus value for initial thread. +// bogus value for the primordial process thread. While the launcher has created +// the VM in a new thread since JDK 6, we still have to allow for the use of the +// JNI invocation API from a primordial thread. void os::Linux::capture_initial_stack(size_t max_size) { - // stack size is the easy part, get it from RLIMIT_STACK - size_t stack_size; + + // max_size is either 0 (which means accept OS default for thread stacks) or + // a user-specified value known to be at least the minimum needed. If we + // are actually on the primordial thread we can make it appear that we have a + // smaller max_size stack by inserting the guard pages at that location. But we + // cannot do anything to emulate a larger stack than what has been provided by + // the OS or threading library. In fact if we try to use a stack greater than + // what is set by rlimit then we will crash the hosting process. + + // Maximum stack size is the easy part, get it from RLIMIT_STACK. + // If this is "unlimited" then it will be a huge value. struct rlimit rlim; getrlimit(RLIMIT_STACK, &rlim); - stack_size = rlim.rlim_cur; + size_t stack_size = rlim.rlim_cur; // 6308388: a bug in ld.so will relocate its own .data section to the // lower end of primordial stack; reduce ulimit -s value a little bit // so we won't install guard page on ld.so's data section. stack_size -= 2 * page_size(); - // 4441425: avoid crash with "unlimited" stack size on SuSE 7.1 or Redhat - // 7.1, in both cases we will get 2G in return value. - // 4466587: glibc 2.2.x compiled w/o "--enable-kernel=2.4.0" (RH 7.0, - // SuSE 7.2, Debian) can not handle alternate signal stack correctly - // for initial thread if its stack size exceeds 6M. Cap it at 2M, - // in case other parts in glibc still assumes 2M max stack size. - // FIXME: alt signal stack is gone, maybe we can relax this constraint? - // Problem still exists RH7.2 (IA64 anyway) but 2MB is a little small - if (stack_size > 2 * K * K IA64_ONLY(*2)) - stack_size = 2 * K * K IA64_ONLY(*2); // Try to figure out where the stack base (top) is. This is harder. // // When an application is started, glibc saves the initial stack pointer in @@ -1249,14 +1258,18 @@ // stack_top could be partially down the page so align it stack_top = align_size_up(stack_top, page_size()); - if (max_size && stack_size > max_size) { - _initial_thread_stack_size = max_size; + // Allowed stack value is minimum of max_size and what we derived from rlimit + if (max_size > 0) { + _initial_thread_stack_size = MIN2(max_size, stack_size); } else { - _initial_thread_stack_size = stack_size; + // Accept the rlimit max, but if stack is unlimited then it will be huge, so + // clamp it at 8MB as we do on Solaris + _initial_thread_stack_size = MIN2(stack_size, 8*M); } _initial_thread_stack_size = align_size_down(_initial_thread_stack_size, page_size()); _initial_thread_stack_bottom = (address)stack_top - _initial_thread_stack_size; + assert(_initial_thread_stack_bottom < (address)stack_top, "overflow!"); } //////////////////////////////////////////////////////////////////////////////// @@ -5016,12 +5029,42 @@ } }; +static int os_cpu_count(const cpu_set_t* cpus) { + int count = 0; + // only look up to the number of configured processors + for (int i = 0; i < os::processor_count(); i++) { + if (CPU_ISSET(i, cpus)) { + count++; + } + } + return count; +} + +// Get the current number of available processors for this process. +// This value can change at any time during a process's lifetime. +// sched_getaffinity gives an accurate answer as it accounts for cpusets. +// If anything goes wrong we fallback to returning the number of online +// processors - which can be greater than the number available to the process. int os::active_processor_count() { - // Linux doesn't yet have a (official) notion of processor sets, - // so just return the number of online processors. - int online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN); - assert(online_cpus > 0 && online_cpus <= processor_count(), "sanity check"); - return online_cpus; + cpu_set_t cpus; // can represent at most 1024 (CPU_SETSIZE) processors + int cpus_size = sizeof(cpu_set_t); + int cpu_count = 0; + + // pid 0 means the current thread - which we have to assume represents the process + if (sched_getaffinity(0, cpus_size, &cpus) == 0) { + cpu_count = os_cpu_count(&cpus); + if (PrintActiveCpus) { + tty->print_cr("active_processor_count: sched_getaffinity processor count: %d", cpu_count); + } + } + else { + cpu_count = ::sysconf(_SC_NPROCESSORS_ONLN); + warning("sched_getaffinity failed (%s)- using online processor count (%d) " + "which may exceed available processors", strerror(errno), cpu_count); + } + + assert(cpu_count > 0 && cpu_count <= processor_count(), "sanity check"); + return cpu_count; } void os::set_native_thread_name(const char *name) {
--- a/src/share/vm/classfile/systemDictionary.cpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/share/vm/classfile/systemDictionary.cpp Thu Feb 16 13:21:41 2017 -0800 @@ -1084,15 +1084,18 @@ THREAD); const char* pkg = "java/"; + size_t pkglen = strlen(pkg); if (!HAS_PENDING_EXCEPTION && !class_loader.is_null() && parsed_name != NULL && - !strncmp((const char*)parsed_name->bytes(), pkg, strlen(pkg))) { + parsed_name->utf8_length() >= (int)pkglen && + !strncmp((const char*)parsed_name->bytes(), pkg, pkglen)) { // It is illegal to define classes in the "java." package from // JVM_DefineClass or jni_DefineClass unless you're the bootclassloader ResourceMark rm(THREAD); char* name = parsed_name->as_C_string(); char* index = strrchr(name, '/'); + assert(index != NULL, "must be"); *index = '\0'; // chop to just the package name while ((index = strchr(name, '/')) != NULL) { *index = '.'; // replace '/' with '.' in package name
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Thu Feb 16 13:21:41 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -631,11 +631,10 @@ double overall_cm_overhead = (double) MaxGCPauseMillis * marking_overhead / (double) GCPauseIntervalMillis; - double cpu_ratio = 1.0 / (double) os::processor_count(); + double cpu_ratio = 1.0 / os::initial_active_processor_count(); double marking_thread_num = ceil(overall_cm_overhead / cpu_ratio); double marking_task_overhead = - overall_cm_overhead / marking_thread_num * - (double) os::processor_count(); + overall_cm_overhead / marking_thread_num * os::initial_active_processor_count(); double sleep_factor = (1.0 - marking_task_overhead) / marking_task_overhead;
--- a/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Thu Feb 16 13:21:41 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,7 +80,7 @@ // Determines how many mutator threads can process the buffers in parallel. uint DirtyCardQueueSet::num_par_ids() { - return (uint)os::processor_count(); + return (uint)os::initial_active_processor_count(); } void DirtyCardQueueSet::initialize(CardTableEntryClosure* cl, Monitor* cbl_mon, Mutex* fl_lock,
--- a/src/share/vm/opto/cfgnode.hpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/share/vm/opto/cfgnode.hpp Thu Feb 16 13:21:41 2017 -0800 @@ -119,6 +119,9 @@ // input in slot 0. class PhiNode : public TypeNode { const TypePtr* const _adr_type; // non-null only for Type::MEMORY nodes. + // The following fields are only used for data PhiNodes to indicate + // that the PhiNode represents the value of a known instance field. + int _inst_mem_id; // Instance memory id (node index of the memory Phi) const int _inst_id; // Instance id of the memory slice. const int _inst_index; // Alias index of the instance memory slice. // Array elements references have the same alias_idx but different offset. @@ -138,11 +141,13 @@ }; PhiNode( Node *r, const Type *t, const TypePtr* at = NULL, + const int imid = -1, const int iid = TypeOopPtr::InstanceTop, const int iidx = Compile::AliasIdxTop, const int ioffs = Type::OffsetTop ) : TypeNode(t,r->req()), _adr_type(at), + _inst_mem_id(imid), _inst_id(iid), _inst_index(iidx), _inst_offset(ioffs) @@ -187,11 +192,14 @@ virtual bool pinned() const { return in(0) != 0; } virtual const TypePtr *adr_type() const { verify_adr_type(true); return _adr_type; } + void set_inst_mem_id(int inst_mem_id) { _inst_mem_id = inst_mem_id; } + const int inst_mem_id() const { return _inst_mem_id; } const int inst_id() const { return _inst_id; } const int inst_index() const { return _inst_index; } const int inst_offset() const { return _inst_offset; } - bool is_same_inst_field(const Type* tp, int id, int index, int offset) { + bool is_same_inst_field(const Type* tp, int mem_id, int id, int index, int offset) { return type()->basic_type() == tp->basic_type() && + inst_mem_id() == mem_id && inst_id() == id && inst_index() == index && inst_offset() == offset &&
--- a/src/share/vm/opto/macro.cpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/share/vm/opto/macro.cpp Thu Feb 16 13:21:41 2017 -0800 @@ -401,7 +401,7 @@ for (DUIterator_Fast kmax, k = region->fast_outs(kmax); k < kmax; k++) { Node* phi = region->fast_out(k); if (phi->is_Phi() && phi != mem && - phi->as_Phi()->is_same_inst_field(phi_type, instance_id, alias_idx, offset)) { + phi->as_Phi()->is_same_inst_field(phi_type, (int)mem->_idx, instance_id, alias_idx, offset)) { return phi; } } @@ -420,7 +420,7 @@ GrowableArray <Node *> values(length, length, NULL, false); // create a new Phi for the value - PhiNode *phi = new (C) PhiNode(mem->in(0), phi_type, NULL, instance_id, alias_idx, offset); + PhiNode *phi = new (C) PhiNode(mem->in(0), phi_type, NULL, mem->_idx, instance_id, alias_idx, offset); transform_later(phi); value_phis->push(phi, mem->_idx);
--- a/src/share/vm/opto/memnode.cpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/share/vm/opto/memnode.cpp Thu Feb 16 13:21:41 2017 -0800 @@ -1155,7 +1155,7 @@ for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) { Node* phi = region->fast_out(i); if (phi->is_Phi() && phi != mem && - phi->as_Phi()->is_same_inst_field(this_type, this_iid, this_index, this_offset)) { + phi->as_Phi()->is_same_inst_field(this_type, (int)mem->_idx, this_iid, this_index, this_offset)) { return phi; } } @@ -1400,7 +1400,7 @@ this_iid = base->_idx; } PhaseIterGVN* igvn = phase->is_IterGVN(); - Node* phi = new (C) PhiNode(region, this_type, NULL, this_iid, this_index, this_offset); + Node* phi = new (C) PhiNode(region, this_type, NULL, mem->_idx, this_iid, this_index, this_offset); for (uint i = 1; i < region->req(); i++) { Node* x; Node* the_clone = NULL;
--- a/src/share/vm/opto/phaseX.cpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/share/vm/opto/phaseX.cpp Thu Feb 16 13:21:41 2017 -0800 @@ -481,6 +481,8 @@ uint current_idx = 0; // The current new node ID. Incremented after every assignment. for (uint i = 0; i < _useful.size(); i++) { Node* n = _useful.at(i); + // Sanity check that fails if we ever decide to execute this phase after EA + assert(!n->is_Phi() || n->as_Phi()->inst_mem_id() == -1, "should not be linked to data Phi"); const Type* type = gvn->type_or_null(n); new_type_array.map(current_idx, type); @@ -1378,6 +1380,18 @@ i -= num_edges; // we deleted 1 or more copies of this edge } + // Search for instance field data PhiNodes in the same region pointing to the old + // memory PhiNode and update their instance memory ids to point to the new node. + if (old->is_Phi() && old->as_Phi()->type()->has_memory() && old->in(0) != NULL) { + Node* region = old->in(0); + for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) { + PhiNode* phi = region->fast_out(i)->isa_Phi(); + if (phi != NULL && phi->inst_mem_id() == (int)old->_idx) { + phi->set_inst_mem_id((int)nn->_idx); + } + } + } + // Smash all inputs to 'old', isolating him completely Node *temp = new (C) Node(1); temp->init_req(0,nn); // Add a use to nn to prevent him from dying
--- a/src/share/vm/opto/type.hpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/share/vm/opto/type.hpp Thu Feb 16 13:21:41 2017 -0800 @@ -882,7 +882,7 @@ // If not InstanceTop or InstanceBot, indicates that this is // a particular instance of this type which is distinct. - // This is the the node index of the allocation node creating this instance. + // This is the node index of the allocation node creating this instance. int _instance_id; // Extra type information profiling gave us. We propagate it the
--- a/src/share/vm/runtime/arguments.cpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/share/vm/runtime/arguments.cpp Thu Feb 16 13:21:41 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1768,10 +1768,39 @@ FLAG_SET_CMDLINE(uintx, MaxRAMFraction, DefaultMaxRAMFraction); } - const julong phys_mem = + julong phys_mem = FLAG_IS_DEFAULT(MaxRAM) ? MIN2(os::physical_memory(), (julong)MaxRAM) : (julong)MaxRAM; + // Experimental support for CGroup memory limits + if (UseCGroupMemoryLimitForHeap) { + // This is a rough indicator that a CGroup limit may be in force + // for this process + const char* lim_file = "/sys/fs/cgroup/memory/memory.limit_in_bytes"; + FILE *fp = fopen(lim_file, "r"); + if (fp != NULL) { + julong cgroup_max = 0; + int ret = fscanf(fp, JULONG_FORMAT, &cgroup_max); + if (ret == 1 && cgroup_max > 0) { + // If unlimited, cgroup_max will be a very large, but unspecified + // value, so use initial phys_mem as a limit + if (PrintGCDetails && Verbose) { + // Cannot use gclog_or_tty yet. + tty->print_cr("Setting phys_mem to the min of cgroup limit (" + JULONG_FORMAT "MB) and initial phys_mem (" + JULONG_FORMAT "MB)", cgroup_max/M, phys_mem/M); + } + phys_mem = MIN2(cgroup_max, phys_mem); + } else { + warning("Unable to read/parse cgroup memory limit from %s: %s", + lim_file, errno != 0 ? strerror(errno) : "unknown error"); + } + fclose(fp); + } else { + warning("Unable to open cgroup memory limit file %s (%s)", lim_file, strerror(errno)); + } + } + // If the maximum heap size has not been set with -Xmx, // then set it as fraction of the size of physical memory, // respecting the maximum and minimum sizes of the heap.
--- a/src/share/vm/runtime/globals.hpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/share/vm/runtime/globals.hpp Thu Feb 16 13:21:41 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2068,6 +2068,10 @@ "Maximum ergonomically set heap size (in bytes); zero means use " \ "MaxRAM / MaxRAMFraction") \ \ + experimental(bool, UseCGroupMemoryLimitForHeap, false, \ + "Use CGroup memory limit as physical memory limit for heap " \ + "sizing") \ + \ product(uintx, MaxRAMFraction, 4, \ "Maximum fraction (1/n) of real memory used for maximum heap " \ "size") \
--- a/src/share/vm/runtime/os.cpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/share/vm/runtime/os.cpp Thu Feb 16 13:21:41 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,6 +78,7 @@ uintptr_t os::_serialize_page_mask = 0; long os::_rand_seed = 1; int os::_processor_count = 0; +int os::_initial_active_processor_count = 0; size_t os::_page_sizes[os::page_sizes_max]; #ifndef PRODUCT @@ -322,6 +323,7 @@ } void os::init_before_ergo() { + initialize_initial_active_processor_count(); // We need to initialize large page support here because ergonomics takes some // decisions depending on large page support and the calculated large page size. large_page_init(); @@ -835,7 +837,11 @@ st->print("CPU:"); st->print("total %d", os::processor_count()); // It's not safe to query number of active processors after crash - // st->print("(active %d)", os::active_processor_count()); + // st->print("(active %d)", os::active_processor_count()); but we can + // print the initial number of active processors. + // We access the raw value here because the assert in the accessor will + // fail if the crash occurs before initialization of this value. + st->print(" (initial active %d)", _initial_active_processor_count); st->print(" %s", VM_Version::cpu_features()); st->cr(); pd_print_cpu_info(st); @@ -1418,6 +1424,11 @@ return result; } +void os::initialize_initial_active_processor_count() { + assert(_initial_active_processor_count == 0, "Initial active processor count already set."); + _initial_active_processor_count = active_processor_count(); +} + void os::SuspendedThreadTask::run() { assert(Threads_lock->owned_by_self() || (_thread == VMThread::vm_thread()), "must have threads lock to call this"); internal_do_task();
--- a/src/share/vm/runtime/os.hpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/share/vm/runtime/os.hpp Thu Feb 16 13:21:41 2017 -0800 @@ -151,6 +151,7 @@ static size_t page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned); + static void initialize_initial_active_processor_count(); public: static void init(void); // Called before command line parsing static void init_before_ergo(void); // Called after command line parsing @@ -238,6 +239,13 @@ // Note that on some OSes this can change dynamically. static int active_processor_count(); + // At startup the number of active CPUs this process is allowed to run on. + // This value does not change dynamically. May be different from active_processor_count(). + static int initial_active_processor_count() { + assert(_initial_active_processor_count > 0, "Initial active processor count not set yet."); + return _initial_active_processor_count; + } + // Bind processes to processors. // This is a two step procedure: // first you generate a distribution of processes to processors, @@ -975,8 +983,9 @@ protected: - static long _rand_seed; // seed for random number generator - static int _processor_count; // number of processors + static long _rand_seed; // seed for random number generator + static int _processor_count; // number of processors + static int _initial_active_processor_count; // number of active processors during initialization. static char* format_boot_path(const char* format_string, const char* home,
--- a/src/share/vm/runtime/vm_version.cpp Mon Jan 23 17:09:40 2017 -0800 +++ b/src/share/vm/runtime/vm_version.cpp Thu Feb 16 13:21:41 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -296,7 +296,7 @@ // processor after the first 8. For example, on a 72 cpu machine // and a chosen fraction of 5/8 // use 8 + (72 - 8) * (5/8) == 48 worker threads. - unsigned int ncpus = (unsigned int) os::active_processor_count(); + unsigned int ncpus = (unsigned int) os::initial_active_processor_count(); return (ncpus <= switch_pt) ? ncpus : (switch_pt + ((ncpus - switch_pt) * num) / den);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/os/AvailableProcessors.java Thu Feb 16 13:21:41 2017 -0800 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.io.File; +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.OutputAnalyzer; +import java.util.ArrayList; + +/* + * @test + * @bug 6515172 + * @summary Check that availableProcessors reports the correct value when running in a cpuset on linux + * @requires os.family == "linux" + * @library /testlibrary + * @build com.oracle.java.testlibrary.* + * @run driver AvailableProcessors + */ +public class AvailableProcessors { + + static final String SUCCESS_STRING = "Found expected processors: "; + + public static void main(String[] args) throws Throwable { + if (args.length > 0) + checkProcessors(Integer.parseInt(args[0])); + else { + // run ourselves under different cpu configurations + // using the taskset command + String taskset; + final String taskset1 = "/bin/taskset"; + final String taskset2 = "/usr/bin/taskset"; + if (new File(taskset1).exists()) + taskset = taskset1; + else if (new File(taskset2).exists()) + taskset = taskset2; + else { + System.out.println("Skipping test: could not find taskset command"); + return; + } + + int available = Runtime.getRuntime().availableProcessors(); + + if (available == 1) { + System.out.println("Skipping test: only one processor available"); + return; + } + + // Get the java command we want to execute + // Enable logging for easier failure diagnosis + ProcessBuilder master = + ProcessTools.createJavaProcessBuilder(false, + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+PrintActiveCpus", + "AvailableProcessors"); + + int[] expected = new int[] { 1, available/2, available-1, available }; + + for (int i : expected) { + System.out.println("Testing for " + i + " processors ..."); + int max = i - 1; + ArrayList<String> cmdline = new ArrayList<>(master.command()); + // prepend taskset command + cmdline.add(0, "0-" + max); + cmdline.add(0, "-c"); + cmdline.add(0, taskset); + // append expected processor count + cmdline.add(String.valueOf(i)); + ProcessBuilder pb = new ProcessBuilder(cmdline); + System.out.println("Final command line: " + + ProcessTools.getCommandLine(pb)); + OutputAnalyzer output = ProcessTools.executeProcess(pb); + output.shouldContain(SUCCESS_STRING); + } + } + } + + static void checkProcessors(int expected) { + int available = Runtime.getRuntime().availableProcessors(); + if (available != expected) + throw new Error("Expected " + expected + " processors, but found " + + available); + else + System.out.println(SUCCESS_STRING + available); + } +}