Mercurial > hg > graal-jvmci-8
view graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java @ 16334:0e36e8377c99
HSAIL: cannot reference OkraContext if it cannot be loaded
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Mon, 30 Jun 2014 21:22:39 +0200 |
parents | 3a537502f40f |
children | 1daaa2c62142 |
line wrap: on
line source
/* * Copyright (c) 2009, 2012, 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. */ package com.oracle.graal.compiler.hsail.test.infra; import static org.junit.Assert.*; import static org.junit.Assume.*; import java.io.*; import java.lang.annotation.*; import java.lang.reflect.*; import java.nio.file.*; import java.util.*; import java.util.concurrent.atomic.*; import java.util.logging.*; import com.amd.okra.*; import com.oracle.graal.test.*; /** * Abstract class on which the HSAIL unit tests are built. Executes a method or lambda on both the * Java side and the Okra side and compares the results for fields that are annotated with * {@link Result}. */ public abstract class KernelTester extends GraalTest { /** * Denotes a field whose value is to be * {@linkplain KernelTester#assertResultFieldsEqual(KernelTester) compared} as part of computing * the result of a test. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Result { } // Using these in case we want to compile with Java 7. public interface MyIntConsumer { void accept(int value); } public interface MyObjConsumer { void accept(Object obj); } public enum DispatchMode { SEQ, JTP, OKRA } public enum HsailMode { COMPILED, INJECT_HSAIL, INJECT_OCL } public DispatchMode dispatchMode; // Where the hsail comes from. private HsailMode hsailMode; protected Method testMethod; // What type of okra dispatch to use when client calls. private boolean useLambdaMethod; private Class<?>[] testMethodParams = null; private int id = nextId.incrementAndGet(); static AtomicInteger nextId = new AtomicInteger(0); public static Logger logger; private OkraContext okraContext; private OkraKernel okraKernel; private static final String propPkgName = KernelTester.class.getPackage().getName(); private static Level logLevel; private static ConsoleHandler consoleHandler; private boolean runOkraFirst = Boolean.getBoolean("kerneltester.runOkraFirst"); static { logger = Logger.getLogger(propPkgName); logLevel = Level.parse(System.getProperty("kerneltester.logLevel", "OFF")); // This block configure the logger with handler and formatter. consoleHandler = new ConsoleHandler(); logger.addHandler(consoleHandler); logger.setUseParentHandlers(false); SimpleFormatter formatter = new SimpleFormatter() { @SuppressWarnings("sync-override") @Override public String format(LogRecord record) { return (record.getMessage() + "\n"); } }; consoleHandler.setFormatter(formatter); setLogLevel(logLevel); } private static boolean gaveNoOkraWarning = false; private boolean onSimulator; private final boolean okraLibExists; public boolean runningOnSimulator() { return onSimulator; } public boolean okraEnvIsInitialized() { return this.okraLibExists; } public KernelTester(boolean okraLibExists) { dispatchMode = DispatchMode.SEQ; hsailMode = HsailMode.COMPILED; useLambdaMethod = false; this.okraLibExists = okraLibExists || OkraUtil.okraLibExists(); if (!this.okraLibExists) { logger.info("Okra native library cannot be found or loaded while running" + this.getClass().getSimpleName()); return; } // Control which okra instances can run the tests (isSimulator is static). onSimulator = OkraContext.isSimulator(); } public abstract void runTest(); /** * Asserts that the value of all {@link Result} annotated fields in this object and * {@code other} are {@linkplain #assertDeepEquals(Object, Object) equal}. * * @throws AssertionError if the value of a result field in this and {@code other} are not equal */ public void assertResultFieldsEqual(KernelTester other) { Class<?> clazz = this.getClass(); while (clazz != null && clazz != KernelTester.class) { for (Field f : clazz.getDeclaredFields()) { if (!Modifier.isStatic(f.getModifiers())) { Result annos = f.getAnnotation(Result.class); if (annos != null) { Object actualResult = getFieldFromObject(f, this); Object expectedResult = getFieldFromObject(f, other); assertDeepEquals(f.toString(), expectedResult, actualResult); } } } clazz = clazz.getSuperclass(); } } public void setDispatchMode(DispatchMode dispatchMode) { this.dispatchMode = dispatchMode; } public void setHsailMode(HsailMode hsailMode) { this.hsailMode = hsailMode; } /** * Return a clone of this instance unless overridden, we just call the null constructor. */ public KernelTester newInstance() { try { return this.getClass().getConstructor((Class<?>[]) null).newInstance(); } catch (Throwable t) { fail("Unexpected exception " + t); return null; } } public Method getMethodFromMethodName(String methName, Class<?> clazz) { Class<?> clazz2 = clazz; while (clazz2 != null) { for (Method m : clazz2.getDeclaredMethods()) { logger.fine(" in " + clazz2 + ", trying to match " + m); if (m.getName().equals(methName)) { testMethodParams = m.getParameterTypes(); if (logLevel.intValue() <= Level.FINE.intValue()) { logger.fine(" in " + clazz2 + ", matched " + m); logger.fine("parameter types are..."); int paramNum = 0; for (Class<?> pclazz : testMethodParams) { logger.fine(paramNum++ + ") " + pclazz.toString()); } } return m; } } // Didn't find it in current clazz, try superclass. clazz2 = clazz2.getSuperclass(); } // If we got this far, no match. return null; } private void setTestMethod(String methName, Class<?> inClazz) { testMethod = getMethodFromMethodName(methName, inClazz); if (testMethod == null) { fail("cannot find method " + methName + " in class " + inClazz); } else { // Print info but only for first such class. if (id == 1) { logger.fine("testMethod to be compiled is \n " + testMethod); } } } // Default is method name "run", but could be overridden. private final String defaultMethodName = "run"; public String getTestMethodName() { return defaultMethodName; } /** * The dispatchMethodKernel dispatches a non-lambda method. All the parameters of the compiled * method are supplied as parameters to this call. */ public void dispatchMethodKernel(int range, Object... args) { if (testMethod == null) { setTestMethod(getTestMethodName(), this.getClass()); } if (dispatchMode == DispatchMode.SEQ) { dispatchMethodKernelSeq(range, args); } else if (dispatchMode == DispatchMode.OKRA) { dispatchMethodKernelOkra(range, args); } } /** * The "array stream" version of {@link #dispatchMethodKernel(int, Object...)}. */ public void dispatchMethodKernel(Object[] ary, Object... args) { if (testMethod == null) { setTestMethod(getTestMethodName(), this.getClass()); } if (dispatchMode == DispatchMode.SEQ) { dispatchMethodKernelSeq(ary, args); } else if (dispatchMode == DispatchMode.OKRA) { dispatchMethodKernelOkra(ary, args); } } /** * This dispatchLambdaMethodKernel dispatches the lambda version of a kernel where the "kernel" * is for the lambda method itself (like lambda$0). */ public void dispatchLambdaMethodKernel(int range, MyIntConsumer consumer) { if (testMethod == null) { setTestMethod(findLambdaMethodName(), this.getClass()); } if (dispatchMode == DispatchMode.SEQ) { dispatchLambdaKernelSeq(range, consumer); } else if (dispatchMode == DispatchMode.OKRA) { dispatchLambdaMethodKernelOkra(range, consumer); } } public void dispatchLambdaMethodKernel(Object[] ary, MyObjConsumer consumer) { if (testMethod == null) { setTestMethod(findLambdaMethodName(), this.getClass()); } if (dispatchMode == DispatchMode.SEQ) { dispatchLambdaKernelSeq(ary, consumer); } else if (dispatchMode == DispatchMode.OKRA) { dispatchLambdaMethodKernelOkra(ary, consumer); } } /** * Dispatches the lambda version of a kernel where the "kernel" is for the xxx$$Lambda.accept * method in the wrapper for the lambda. Note that the useLambdaMethod boolean provides a way of * actually invoking dispatchLambdaMethodKernel from this API. */ public void dispatchLambdaKernel(int range, MyIntConsumer consumer) { if (useLambdaMethod) { dispatchLambdaMethodKernel(range, consumer); return; } if (testMethod == null) { setTestMethod("accept", consumer.getClass()); } if (dispatchMode == DispatchMode.SEQ) { dispatchLambdaKernelSeq(range, consumer); } else if (dispatchMode == DispatchMode.OKRA) { dispatchLambdaKernelOkra(range, consumer); } } public void dispatchLambdaKernel(Object[] ary, MyObjConsumer consumer) { if (useLambdaMethod) { dispatchLambdaMethodKernel(ary, consumer); return; } if (testMethod == null) { setTestMethod("accept", consumer.getClass()); } if (dispatchMode == DispatchMode.SEQ) { dispatchLambdaKernelSeq(ary, consumer); } else if (dispatchMode == DispatchMode.OKRA) { dispatchLambdaKernelOkra(ary, consumer); } } private ArrayList<String> getLambdaMethodNames() { Class<?> clazz = this.getClass(); ArrayList<String> lambdaNames = new ArrayList<>(); while (clazz != null && (lambdaNames.size() == 0)) { for (Method m : clazz.getDeclaredMethods()) { logger.fine(" in " + clazz + ", trying to match " + m); if (m.getName().startsWith("lambda$")) { lambdaNames.add(m.getName()); } } // Didn't find it in current clazz, try superclass. clazz = clazz.getSuperclass(); } return lambdaNames; } /** * findLambdaMethodName finds a name in the class starting with lambda$. If we find more than * one, throw an error, and tell user to override explicitly */ private String findLambdaMethodName() { // If user overrode getTestMethodName, use that name. if (!getTestMethodName().equals(defaultMethodName)) { return getTestMethodName(); } else { ArrayList<String> lambdaNames = getLambdaMethodNames(); switch (lambdaNames.size()) { case 1: return lambdaNames.get(0); case 0: fail("No lambda method found in " + this.getClass()); return null; default: // More than one lambda. String msg = "Multiple lambda methods found in " + this.getClass() + "\nYou should override getTestMethodName with one of the following\n"; for (String name : lambdaNames) { msg = msg + name + "\n"; } fail(msg); return null; } } } /** * The getCompiledHSAILSource returns the string of HSAIL code for the compiled method. By * default, throws an error. In graal for instance, this would be overridden in * GraalKernelTester. */ public String getCompiledHSAILSource(Method testMethod1) { fail("no compiler connected so unable to compile " + testMethod1 + "\nYou could try injecting HSAIL or OpenCL"); return null; } public String getHSAILSource(Method testMethod1) { switch (hsailMode) { case COMPILED: return getCompiledHSAILSource(testMethod1); case INJECT_HSAIL: return getHsailFromClassnameHsailFile(); case INJECT_OCL: return getHsailFromClassnameOclFile(); default: fail("unknown hsailMode = " + hsailMode); return null; } } /** * The getHSAILKernelName returns the name of the hsail kernel. By default we use 'run'. unless * coming from opencl injection. Could be overridden by the junit test. */ public String getHSAILKernelName() { return (hsailMode != HsailMode.INJECT_OCL ? "&run" : "&__OpenCL_run_kernel"); } private void createOkraKernel() { // Call routines in the derived class to get the hsail code and kernel name. String hsailSource = getHSAILSource(testMethod); if (!okraLibExists) { if (!gaveNoOkraWarning) { logger.severe("No Okra library detected, skipping all KernelTester tests in " + this.getClass().getPackage().getName()); gaveNoOkraWarning = true; } } // Ignore any kerneltester test if okra does not exist. assumeTrue(okraLibExists); // Control which okra instances can run the tests. onSimulator = OkraContext.isSimulator(); okraContext = new OkraContext(); if (!okraContext.isValid()) { fail("...unable to create context"); } // Control verbosity in okra from our logLevel. if (logLevel.intValue() <= Level.INFO.intValue()) { okraContext.setVerbose(true); } okraKernel = new OkraKernel(okraContext, hsailSource, getHSAILKernelName()); if (!okraKernel.isValid()) { fail("...unable to create kernel"); } } /** * Dispatches an okra kernel over a given range using JNI. Protected so that it can be * overridden in {@link GraalKernelTester} which will dispatch without JNI. */ protected void dispatchKernelOkra(int range, Object... args) { if (okraKernel == null) { createOkraKernel(); } if (logLevel.intValue() <= Level.FINE.intValue()) { logger.fine("Arguments passed to okra..."); for (Object arg : args) { logger.fine(" " + arg); } } okraKernel.setLaunchAttributes(range); okraKernel.dispatchWithArgs(args); } // int stream version private void dispatchMethodKernelSeq(int range, Object... args) { Object[] invokeArgs = new Object[args.length + 1]; // Need space on the end for the gid parameter. System.arraycopy(args, 0, invokeArgs, 0, args.length); int gidArgIndex = invokeArgs.length - 1; if (logLevel.intValue() <= Level.FINE.intValue()) { for (Object arg : args) { logger.fine(arg.toString()); } } for (int rangeIndex = 0; rangeIndex < range; rangeIndex++) { invokeArgs[gidArgIndex] = rangeIndex; invokeMethodKernelSeq(invokeArgs, rangeIndex); } } // array stream version private void dispatchMethodKernelSeq(Object[] ary, Object... args) { Object[] invokeArgs = new Object[args.length + 1]; // Need space on the end for the final obj parameter. System.arraycopy(args, 0, invokeArgs, 0, args.length); int objArgIndex = invokeArgs.length - 1; if (logLevel.intValue() <= Level.FINE.intValue()) { for (Object arg : args) { logger.fine(arg.toString()); } } int range = ary.length; for (int rangeIndex = 0; rangeIndex < range; rangeIndex++) { invokeArgs[objArgIndex] = ary[rangeIndex]; invokeMethodKernelSeq(invokeArgs, rangeIndex); } } private void invokeMethodKernelSeq(Object[] invokeArgs, int rangeIndex) { try { testMethod.invoke(this, invokeArgs); } catch (IllegalAccessException e) { fail("could not invoke " + testMethod + ", make sure it is public"); } catch (IllegalArgumentException e) { fail("wrong arguments invoking " + testMethod + ", check number and type of args passed to dispatchMethodKernel"); } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause instanceof RuntimeException) { throw ((RuntimeException) cause); } else { String errstr = testMethod + " threw a checked exception on gid=" + rangeIndex + ", exception was " + cause; fail(errstr); } } catch (Exception e) { fail("Unknown exception " + e + " invoking " + testMethod); } } // int stream version private void dispatchMethodKernelOkra(int range, Object... args) { Object[] fixedArgs = fixArgTypes(args); if (Modifier.isStatic(testMethod.getModifiers())) { dispatchKernelOkra(range, fixedArgs); } else { // If it is a non-static method we have to push "this" as the first argument. Object[] newFixedArgs = new Object[fixedArgs.length + 1]; System.arraycopy(fixedArgs, 0, newFixedArgs, 1, fixedArgs.length); newFixedArgs[0] = this; dispatchKernelOkra(range, newFixedArgs); } } // array stream version private void dispatchMethodKernelOkra(Object[] ary, Object... args) { // add the ary itself as the last arg in the passed parameter list Object[] argsWithAry = new Object[args.length + 1]; System.arraycopy(args, 0, argsWithAry, 0, args.length); argsWithAry[argsWithAry.length - 1] = ary; Object[] fixedArgs = fixArgTypes(argsWithAry); int range = ary.length; if (Modifier.isStatic(testMethod.getModifiers())) { dispatchKernelOkra(range, fixedArgs); } else { // If it is a non-static method we have to push "this" as the first argument. Object[] newFixedArgs = new Object[fixedArgs.length + 1]; System.arraycopy(fixedArgs, 0, newFixedArgs, 1, fixedArgs.length); newFixedArgs[0] = this; dispatchKernelOkra(range, newFixedArgs); } } /** * For primitive arg parameters, make sure arg types are cast to whatever the testMethod * signature says they should be. */ protected Object[] fixArgTypes(Object[] args) { Object[] fixedArgs = new Object[args.length]; for (int i = 0; i < args.length; i++) { Class<?> paramClass = testMethodParams[i]; if (paramClass.equals(Float.class) || paramClass.equals(float.class)) { fixedArgs[i] = ((Number) args[i]).floatValue(); } else if (paramClass.equals(Integer.class) || paramClass.equals(int.class)) { fixedArgs[i] = ((Number) args[i]).intValue(); } else if (paramClass.equals(Long.class) || paramClass.equals(long.class)) { fixedArgs[i] = ((Number) args[i]).longValue(); } else if (paramClass.equals(Double.class) || paramClass.equals(double.class)) { fixedArgs[i] = ((Number) args[i]).doubleValue(); } else if (paramClass.equals(Byte.class) || paramClass.equals(byte.class)) { fixedArgs[i] = ((Number) args[i]).byteValue(); } else if (paramClass.equals(Boolean.class) || paramClass.equals(boolean.class)) { fixedArgs[i] = (boolean) args[i]; } else { // All others just move unchanged. fixedArgs[i] = args[i]; } } return fixedArgs; } /** * Dispatching a lambda on the java side is simple. */ @SuppressWarnings("static-method") private void dispatchLambdaKernelSeq(int range, MyIntConsumer consumer) { for (int i = 0; i < range; i++) { consumer.accept(i); } } @SuppressWarnings("static-method") private void dispatchLambdaKernelSeq(Object[] ary, MyObjConsumer consumer) { for (Object obj : ary) { consumer.accept(obj); } } /** * The dispatchLambdaMethodKernelOkra dispatches in the case where the hsail kernel implements * the lambda method itself as opposed to the wrapper that calls the lambda method. From the * consumer object, we need to find the fields and pass them to the kernel. */ protected void dispatchLambdaMethodKernelOkra(int range, MyIntConsumer consumer) { logger.info("To determine parameters to pass to hsail kernel, we will examine " + consumer.getClass()); Field[] fields = consumer.getClass().getDeclaredFields(); Object[] args = new Object[fields.length]; int argIndex = 0; for (Field f : fields) { logger.info("... " + f); args[argIndex++] = getFieldFromObject(f, consumer); } dispatchKernelOkra(range, args); } private void dispatchLambdaMethodKernelOkra(Object[] ary, MyObjConsumer consumer) { logger.info("To determine parameters to pass to hsail kernel, we will examine " + consumer.getClass()); Field[] fields = consumer.getClass().getDeclaredFields(); Object[] args = new Object[fields.length + 1]; // + 1 because we also pass the array int argIndex = 0; for (Field f : fields) { logger.info("... " + f); args[argIndex++] = getFieldFromObject(f, consumer); } args[argIndex] = ary; dispatchKernelOkra(ary.length, args); } /** * The dispatchLambdaKernelOkra dispatches in the case where the hsail kernel where the hsail * kernel implements the accept method of the wrapper that calls the lambda method as opposed to * the actual lambda method itself. */ private void dispatchLambdaKernelOkra(int range, MyIntConsumer consumer) { // The "wrapper" method always has only one arg consisting of the consumer. Object[] args = new Object[1]; args[0] = consumer; dispatchKernelOkra(range, args); } private void dispatchLambdaKernelOkra(Object[] ary, MyObjConsumer consumer) { // The "wrapper" method always has only one arg consisting of the consumer. Object[] args = new Object[2]; args[0] = consumer; args[1] = ary; dispatchKernelOkra(ary.length, args); } private void disposeKernelOkra() { if (okraContext != null) { okraContext.dispose(); } } private void assertOkraEqualsSeq(HsailMode hsailModeToUse) { assertOkraEqualsSeq(hsailModeToUse, false); } /** * Runs this instance on OKRA, and as SEQ and compares the output of the two executions. the * runOkraFirst flag controls which order they are done in. Note the compiler must use eager * resolving if Okra is done first. */ private void assertOkraEqualsSeq(HsailMode hsailModeToUse, boolean useLambda) { KernelTester testerSeq; if (runOkraFirst) { runOkraInstance(hsailModeToUse, useLambda); testerSeq = runSeqInstance(); } else { testerSeq = runSeqInstance(); runOkraInstance(hsailModeToUse, useLambda); } assertResultFieldsEqual(testerSeq); } private void runOkraInstance(HsailMode hsailModeToUse, boolean useLambda) { // run Okra instance in exiting KernelTester object this.setHsailMode(hsailModeToUse); this.setDispatchMode(DispatchMode.OKRA); this.useLambdaMethod = useLambda; this.runTest(); this.disposeKernelOkra(); } private KernelTester runSeqInstance() { // Create and run sequential instance. KernelTester testerSeq = newInstance(); testerSeq.setDispatchMode(DispatchMode.SEQ); testerSeq.runTest(); return testerSeq; } public void testGeneratedHsail() { assertOkraEqualsSeq(HsailMode.COMPILED); } public void testGeneratedHsailUsingLambdaMethod() { assertOkraEqualsSeq(HsailMode.COMPILED, true); } public void testInjectedHsail() { newInstance().assertOkraEqualsSeq(HsailMode.INJECT_HSAIL); } public void testInjectedOpencl() { newInstance().assertOkraEqualsSeq(HsailMode.INJECT_OCL); } protected static Object getFieldFromObject(Field f, Object fromObj) { try { f.setAccessible(true); Type type = f.getType(); logger.info("type = " + type); if (type == double.class) { return f.getDouble(fromObj); } else if (type == float.class) { return f.getFloat(fromObj); } else if (type == long.class) { return f.getLong(fromObj); } else if (type == int.class) { return f.getInt(fromObj); } else if (type == byte.class) { return f.getByte(fromObj); } else if (type == boolean.class) { return f.getBoolean(fromObj); } else { return f.get(fromObj); } } catch (Exception e) { fail("unable to get field " + f + " from " + fromObj); return null; } } public static void checkFileExists(String fileName) { assertTrue(fileName + " does not exist", fileExists(fileName)); } public static boolean fileExists(String fileName) { return new File(fileName).exists(); } public static String getFileAsString(String sourceFileName) { String source = null; try { checkFileExists(sourceFileName); source = new String(Files.readAllBytes(FileSystems.getDefault().getPath(sourceFileName))); } catch (IOException e) { fail("could not open file " + sourceFileName); return null; } return source; } public static String getHsailFromFile(String sourceFileName) { logger.severe("... getting hsail from file " + sourceFileName); return getFileAsString(sourceFileName); } private static void executeCmd(String... cmd) { logger.info("spawning" + Arrays.toString(cmd)); try { ProcessBuilder pb = new ProcessBuilder(cmd); Process p = pb.start(); if (logLevel.intValue() <= Level.INFO.intValue()) { InputStream in = p.getInputStream(); BufferedInputStream buf = new BufferedInputStream(in); InputStreamReader inread = new InputStreamReader(buf); BufferedReader bufferedreader = new BufferedReader(inread); String line; while ((line = bufferedreader.readLine()) != null) { logger.info(line); } } p.waitFor(); } catch (Exception e) { fail("could not execute <" + Arrays.toString(cmd) + ">"); } } public static String getHsailFromOpenCLFile(String openclFileName) { String openclHsailFile = "opencl_out.hsail"; String tmpTahitiFile = "_temp_0_Tahiti.txt"; checkFileExists(openclFileName); logger.severe("...converting " + openclFileName + " to HSAIL..."); executeCmd("aoc2", "-m64", "-I./", "-march=hsail", openclFileName); if (fileExists(tmpTahitiFile)) { return getFileAsString(tmpTahitiFile); } else { executeCmd("HSAILasm", "-disassemble", "-o", openclHsailFile, openclFileName.replace(".cl", ".bin")); checkFileExists(openclHsailFile); return getFileAsString(openclHsailFile); } } public String getHsailFromClassnameHsailFile() { return (getHsailFromFile(this.getClass().getSimpleName() + ".hsail")); } public String getHsailFromClassnameOclFile() { return (getHsailFromOpenCLFile(this.getClass().getSimpleName() + ".cl")); } public static void logInfo(String msg) { logger.info(msg); } public static void logSevere(String msg) { logger.severe(msg); } public static void setLogLevel(Level level) { logLevel = level; logger.setLevel(level); consoleHandler.setLevel(level); } }